题目链接:Click here~~
题意:
n 个点的无向图,边权值为距离,点权值为油价。你开着一辆油箱容量为 c 的坦克,从 s 到 e。问最少花费多少钱。
解题思路:
很容易想到状态, dp[i][j] 表示 到达 i 点剩余油量为 j 的时候的最小花费。
转移的时候,只有两种情况:加油 or 出发去下一节点。
加油时候只需要考虑加1升即可。因为如果加两升可以达到最优状态,那么加1升的状态再加1升同样可以扩展到最优状态。
出发去下一节点的时候,费用不变,剩余油量减少,油量不够不能到达。
但是不好找到最优状态,所以要用节点存储状态,然后用优先队列,每次弹出的节点(cost 最小)一定是最优状态。
写出来很像 bfs 啊。那就叫他 bfs 吧。
#include <queue> #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; const int N = 1e3 + 3; template<int N,int M> struct Graph { int top; struct Vertex{ int head; }V[N]; struct Edge{ int v,w,next; }E[M]; void init(){ memset(V,-1,sizeof(V)); top = 0; } void add_edge(int u,int v,int w){ E[top].v = v; E[top].w = w; E[top].next = V[u].head; V[u].head = top++; } }; Graph<1003,10003*2> g; int price[N]; bool vis[N][103]; struct Node { int u,vol,cost; Node(int u,int vol,int co):u(u),vol(vol),cost(co){} bool operator < (const Node& S) const{ return cost > S.cost; } bool vis(){ return ::vis[u][vol]; } Node plusOil(){ return Node(u,vol+1,cost+price[u]); } }; int bfs(int s,int e,int cp) { priority_queue<Node> Q; Q.push(Node(s,0,0)); while(!Q.empty()) { Node Cur = Q.top(); Q.pop(); int u = Cur.u; if(Cur.vis()) continue; else vis[u][Cur.vol] = true; if(u == e) return Cur.cost; if(Cur.vol + 1 <= cp) { Node Next = Cur.plusOil(); if(!Next.vis()) Q.push(Next); } for(int i=g.V[u].head;~i;i=g.E[i].next) { int v = g.E[i].v; int d = g.E[i].w; if(Cur.vol >= d) { Node Next(v,Cur.vol-d,Cur.cost); if(!Next.vis()) Q.push(Next); } } } return -1; } int main() { int n,m,Q; while(~scanf("%d%d",&n,&m)) { g.init(); for(int i=0;i<n;i++) scanf("%d",&price[i]); for(int i=0;i<m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); g.add_edge(u,v,w); g.add_edge(v,u,w); } scanf("%d",&Q); while(Q--) { memset(vis,false,sizeof(vis)); int cp,s,e; scanf("%d%d%d",&cp,&s,&e); int ans = bfs(s,e,cp); if(ans == -1) puts("impossible"); else printf("%d\n",ans); } } return 0; }