题意:给出一张图,n<=1000,m<=10000. 有一辆车想从图的一个地方到达另外一个地方,每个点是一个卖油的地方,每个地方买的有价格不一样,车的最大装油量是c,求初始点到终止点的最小花费。
网上大部分的思路都是类似于dij的那种扩展。
首先定义一个二维数组dp。 dp[i][j] 表示走到i点剩余j个单位的汽油时的最小花费
然后维护一个优先队列。 每次有两种可扩展的状态,一是加一个单位的油,二是走向邻接点,然后不断的将状态加入优先队列中
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#define MAXN 1005
#define MAXM 100005
#define INF 1000000000
using namespace std;
struct Edge
{int v, w, next;
}edge[MAXM];
struct Node
{int v, cost, f;bool operator <(const Node &a) const{return a.cost < cost;}
};
int head[MAXN], e, n, m, cap;
int dp[MAXN][105], used[MAXN][105], p[MAXN];
int s, t, ask;
priority_queue<Node>q;
void init()
{memset(head, -1, sizeof(head));e = 0;
}
void ready()
{for(int i = 0; i < n; i++)for(int j = 0; j <= 100; j++)dp[i][j] = INF;dp[s][0] = 0;memset(used, 0, sizeof(used));while(!q.empty()) q.pop();
}
void insert(int x, int y, int w)
{edge[e].v = y;edge[e].w = w;edge[e].next = head[x];head[x] = e++;
}
int bfs()
{Node a, b;a.v = s, a.cost = 0, a.f = 0;q.push(a);while(!q.empty()){a = q.top();q.pop();int u = a.v;int cost = a.cost;int f = a.f;used[u][f] = 1;if(u == t) return cost;if(f + 1 <= cap && !used[u][f + 1] && dp[u][f + 1] > dp[u][f] + p[u]){dp[u][f + 1] = dp[u][f] + p[u];b.v = u;b.f = f + 1;b.cost = dp[u][f + 1];q.push(b);}for(int i = head[u]; i != -1; i = edge[i].next){int v = edge[i].v;int w = edge[i].w;if(f >= w && !used[v][f - w] && dp[v][f - w] > cost){dp[v][f - w] = cost;b.v = v;b.f = f - w;b.cost = dp[v][f - w];q.push(b);}}}return -1;
}
int main()
{int x, y, w;scanf("%d%d", &n, &m);init();for(int i = 0; i < n; i++) scanf("%d", &p[i]);while(m--){scanf("%d%d%d", &x, &y, &w);insert(x, y, w);insert(y, x, w);}scanf("%d", &ask);while(ask--){scanf("%d%d%d", &cap, &s, &t);ready();int ans = bfs();if(ans != -1) printf("%d\n", ans);else printf("impossible\n");}return 0;
}