UVA-11280 Flying to Fredericton (dijkstra)
题目大意:一张有向图,n个节点,m条边,有边权。求从起点到终点在最多经过s个中间节点(不包括始末点)时的最小权和。
题目分析:因为起点和终点是固定的,只需一次dijkstra打出表dis[u][k],查表即可。dis[u][k]表示经过k个中间节点到达u点时的最小费用。要注意,经过的中间节点数不会超过n。
代码如下:
# include<iostream> # include<cstdio> # include<map> # include<vector> # include<string> # include<queue> # 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)) const int N=105; const int INF=1<<30; struct Edge { int to,nxt,w; }; Edge e[N*20]; int inq[N][N],dis[N][N],head[N],n,m,cnt; map<string,int>mp; struct Node { int u,k; Node(int _u,int _k):u(_u),k(_k){} }; void dijkstra(int s) { REP(i,1,n+2) REP(j,0,n+2) dis[i][j]=INF; CL(inq,0); queue<Node>q; q.push(Node(s,0)); dis[s][0]=0; inq[s][0]=1; while(!q.empty()) { Node top=q.front(); q.pop(); int u=top.u,k=top.k; inq[u][k]=0; for(int i=head[u];i!=-1;i=e[i].nxt){ int v=e[i].to; if(dis[v][k+1]>dis[u][k]+e[i].w){ dis[v][k+1]=dis[u][k]+e[i].w; if(!inq[v][k+1]){ inq[v][k+1]=1; q.push(Node(v,k+1)); } } } } } void add(int u,int v,int w) { e[cnt].to=v; e[cnt].w=w; e[cnt].nxt=head[u]; head[u]=cnt++; } int main() { int T,w,query,cas=0; string p,q; scanf("%d",&T); while(T--) { scanf("%d",&n); mp.clear(); cnt=0; CL(head,-1); REP(i,1,n+1){ cin>>p; mp[p]=i; } scanf("%d",&m); while(m--) { cin>>p>>q>>w; add(mp[p],mp[q],w); } printf("Scenario #%d\n",++cas); int s=mp["Calgary"],t=mp["Fredericton"]; dijkstra(s); scanf("%d",&query); while(query--) { scanf("%d",&w); w=min(w,n); int ans=INF; REP(i,1,w+2) ans=min(ans,dis[t][i]); if(ans==INF) printf("No satisfactory flights\n"); else printf("Total cost of flight(s) is $%d\n",ans); } if(T) printf("\n"); } return 0; }