题目大意:一张有向图,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;
}