题目链接: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;
}