题目大意:有A个村庄,B个城市,m条边,从起点到终点,找一条最短路径。但是,有一种工具可以使人不费力的移动L个长度,但始末点必须是城市或村庄。这种工具有k个,每个只能使用一次,并且在城市内部不可使用,但在村庄内部可使用。另外,在城市或村庄内部的时间不计。
题目分析:在城市内部不可使用但在村庄内部可使用的意思就是使用这种工具可以穿过多个村庄(如果长度允许)但不可穿过多个城市,即在使用这种工具的始末点之间可以有多个村庄但不可以有城市,无论始末点是什么。这样,可以先处理出任意两个城市或村庄之间的最短距离(中间不允许经过城市),然后再dijkstra。
代码如下:
# include<iostream> # include<cstdio> # include<queue> # include<vector> # include<cstring> # include<algorithm> using namespace std; # define REP(i,s,n) for(int i=s;i<n;++i) # define CL(a,b) memset(a,b,sizeof(a)) # define CLL(a,b,n) fill(a,a+n,b) const int INF=1<<30; struct Node { int u,k; Node(int _u,int _k):u(_u),k(_k){} }; int n,m,A,B,L,K,d[105][12],vis[105][12],G[105][105]; int dijkstra() { REP(i,0,n) REP(j,0,K+1) d[i][j]=INF; CL(vis,0); queue<Node>q; d[n-1][K]=0; vis[n-1][K]=1; q.push(Node(n-1,K)); while(!q.empty()) { Node top=q.front(); q.pop(); int u=top.u,k=top.k; REP(v,0,n){ if(G[u][v]==INF||v==u) continue; if(d[v][k]>d[u][k]+G[u][v]){ d[v][k]=d[u][k]+G[u][v]; if(!vis[v][k]){ vis[v][k]=1; q.push(Node(v,k)); } } if(k>0&&L>=G[u][v]&&d[v][k-1]>d[u][k]){ d[v][k-1]=d[u][k]; if(!vis[v][k-1]){ vis[v][k-1]=1; q.push(Node(v,k-1)); } } } vis[u][k]=0; } int ans=INF; REP(i,0,K+1) ans=min(ans,d[0][i]); return ans; } void floyd() { REP(k,0,A) REP(i,0,n) REP(j,0,n) if(G[i][k]!=INF&&G[k][j]!=INF&&G[i][j]>G[i][k]+G[k][j]) G[i][j]=G[i][k]+G[k][j]; } int main() { int T,a,b,c; scanf("%d",&T); while(T--) { scanf("%d%d%d%d%d",&A,&B,&m,&L,&K); n=A+B; REP(i,0,n) REP(j,0,n) G[i][j]=INF; while(m--) { scanf("%d%d%d",&a,&b,&c); --a,--b; G[a][b]=G[b][a]=min(G[a][b],c); } floyd(); printf("%d\n",dijkstra()); } return 0; }