这题限制较高。一般的算法过不了。自己做起来很吃力。到网上参考牛人代码为之惊叹,处理方法真是不可思议。佩服!佩服!
这题难点就是如何判断汽车加油的问题。为什么加油是一升一升地加。主要是设计的dp搜索是关于路径与油的体积的状态。我认为非常巧妙。
把问题简化了许多,能用的dp的思想和优先队列来进行搜索,为之叫绝。稍微简化了代码,时间也减小了点,心里还是稍有点欣喜。
#include<cstdio>
#include<queue>
#include<cstring>
#define N 1005
#define INF 100000000
using namespace std;
struct q{ //优先队列
int x,d,cost;
q(int a,int b,int c):x(a),d(b),cost(c){} //构造函数。
bool operator<(const q &b)const //运算符重载
{
return b.cost<cost;
}
};
struct node{
int x,cost,next;
}edge[N*20];
int n,m,cnt;
int w[N][105],head[N],money[N];
bool visit[N][105];
void addate(int a,int b,int c)
{
edge[cnt].x=b;
edge[cnt].cost=c;
edge[cnt].next=head[a];
head[a]=cnt++;
}
int BFS(int beg,int end,int v)
{
int i,j,L,x;
priority_queue<q>Q;
// while(!Q.empty()) Q.pop();
memset(visit,0,sizeof(visit));
for(i=0;i<=n;i++)
for(j=0;j<=v;j++)
w[i][j]=INF;
w[beg][0]=0;
Q.push(q(beg,0,0));
while(!Q.empty()){
q cur=Q.top();
Q.pop();
visit[cur.x][cur.d]=1;
if(cur.x==end) return cur.cost; //因为是优先队列,先出来的必定是最优解。
if(cur.d+1<=v&& !visit[cur.x][cur.d+1] && w[cur.x][cur.d+1]>w[cur.x][cur.d]+money[cur.x]){
w[cur.x][cur.d+1]=w[cur.x][cur.d]+money[cur.x];
Q.push(q(cur.x,cur.d+1,w[cur.x][cur.d+1]));
}
for(i=head[cur.x];i!=-1;i=edge[i].next){
x=edge[i].x;
L=edge[i].cost;
if(cur.d>=L&&!visit[x][cur.d-L]&&w[x][cur.d-L]>cur.cost)
{ //如果当前剩下油体积大于下个路径耗油的量,直接进行扩展
w[x][cur.d-L]=cur.cost;
Q.push(q(x,cur.d-L,cur.cost));
}
}
}
return -1; //返回值不能为零,为零就wa了。
}
int main()
{
int i,x,v,c,t,res;
while(scanf("%d%d",&n,&m)!=EOF){
cnt=0;
memset(head,-1,sizeof(head));
for(i=0;i<n;i++)
scanf("%d",&money[i]);
while(m--){
scanf("%d%d%d",&x,&v,&c);
addate(x,v,c);
addate(v,x,c); //构造双向边。
}
scanf("%d",&t);
while(t--){
scanf("%d%d%d",&v,&x,&c);
res=BFS(x,c,v);
if(res!=-1)
printf("%d\n",res);
else
puts("impossible");
}
}
return 0;
}