题意:有A个村庄,B个城堡,给出M条路和长度。超级马里奥和公主要从最后一个城堡走到第一个村庄,单位时间走单位距离。他有一个能瞬移的玩意,可以在村庄/城堡开始/停止瞬移,瞬移到城堡必须停,最大瞬移距离为L,最多瞬移K次。求最短时间。
思路:搜索。开一个数组vis[i][j][k],保存的是时间,i是节点编号,j是剩余瞬移次数,k是当前瞬移已经瞬移的距离,搜索中遇到比原vis[i][j][k]更优的值才往下深入。这种题在之前我看来是不能做的,现在遇到这种题居然把它A掉了!!!
#include <iostream> #include <stdio.h> #include <cmath> #include <algorithm> #include <iomanip> #include <cstdlib> #include <string> #include <memory.h> #include <vector> #include <queue> #include <stack> #include <ctype.h> #define INF 1000000 using namespace std; struct edge{ int v; int w; }; struct node{ int u; int t;//已花时间 int dis;//本次飞的距离 int k;//剩余次数 node(int p0,int p1,int p2,int p3){u=p0;t=p1;dis=p2;k=p3;} }; int vis[110][15][1010]; int main(){ int T; cin>>T; int A,B,M,L,K; while(T--){ vector<edge> E[110]; cin>>A>>B>>M>>L>>K; for(int i=1;i<=A+B;i++){ for(int j=0;j<=K;j++) for(int k=0;k<=L;k++)vis[i][j][k]=INF; } int u,v,w; for(int i=1;i<=M;i++){ cin>>u>>v>>w; edge e;e.v=v;e.w=w; E[u].push_back(e); edge e2;e2.v=u;e2.w=w; E[v].push_back(e2); } int ans=INF; queue<node> que; node start(A+B,0,0,K); vis[A+B][K][0]=0; que.push(start); while(!que.empty()){ node cur=que.front();que.pop(); for(int i=0;i<E[cur.u].size();i++){ //走 node newn(E[cur.u][i].v,cur.t+E[cur.u][i].w,0,cur.k); if( newn.t<vis[newn.u][newn.k][newn.dis] ){ que.push(newn); vis[newn.u][newn.k][newn.dis]=newn.t; if(newn.u==1&&newn.t<ans)ans=newn.t; } //开始瞬移 if(E[cur.u][i].w<=L&&cur.k){ node newn(E[cur.u][i].v,cur.t,E[cur.u][i].w,cur.k-1); if( newn.t<vis[newn.u][newn.k][newn.dis] ){ que.push(newn); vis[newn.u][newn.k][newn.dis]=newn.t; if(newn.u==1&&newn.t<ans)ans=newn.t; } } //继续瞬移 if(cur.dis!=0){ if(cur.u<=A&&cur.dis+E[cur.u][i].w<=L){ node newn(E[cur.u][i].v,cur.t,cur.dis+E[cur.u][i].w,cur.k); if( newn.t<vis[newn.u][newn.k][newn.dis] ){ que.push(newn); vis[newn.u][newn.k][newn.dis]=newn.t; if(newn.u==1&&newn.t<ans)ans=newn.t; } } } } } cout<<ans<<endl; } return 0; }