【题目描述】:
给定一个n个点m条边的有向图,有k个标记点,要求从规定的起点按任意顺序经过所有标记点到达规定的终点,问最短的距离是多少。
【输入描述】:
第一行5个整数n、m、k、s、t,表示点个数、边条数、标记点个数、起点编号、终点编号。
接下来m行每行3个整数x、y、z,表示有一条从x到y的长为z的有向边。
接下来k行每行个整数表示标记点编号。
【输出描述】:
输出一个整数,表示最短距离,若没有方案可行输出-1。
【样例输入】:
3 3 2 1 1
1 2 1
2 3 1
3 1 1
2
3
【样例输出】:
3
【样例说明】:
路径为1->2->3->1。
【时间限制、数据范围及描述】:
时间:1s 空间:256M
20%的数据n<=10。
50%的数据n<=1000。
另有20%的数据k=0。
100%的数据n<=50000,m<=100000,0<=k<=10,1<=z<=5000。
【解题思路】
模板题,最短路+dfs
【code】
1 #include2 #include long,int>,vector3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 using namespace std; 10 const int N=100005,M=15; 11 long long INF=0x7fffffffffffffff; 12 using namespace std; 13 int n,m,k,S,T,flag[M],head[N],Next[N],to[N],val[N],cnt; 14 long long f[M][M],d[N],ans=INF,sum; 15 bool visit[N],vis[M]; 16 priority_queue long long long,int> >,greater long long,int> > >q; 17 void add(int x,int y,int z){ 18 to[++cnt]=y; 19 val[cnt]=z; 20 Next[cnt]=head[x]; 21 head[x]=cnt; 22 } 23 void dijkstra(int s){ 24 for(int i=1;i<=n;i++){ 25 d[i]=INF; 26 } 27 memset(visit,0,sizeof(visit)); 28 d[s]=0; 29 q.push(make_pair(d[s],s)); 30 while(!q.empty()){ 31 int x=q.top().second; 32 q.pop(); 33 if(visit[x]){ 34 continue; 35 } 36 visit[x]=1; 37 for(int i=head[x];i;i=Next[i]){ 38 int y=to[i]; 39 if(d[y]>d[x]+val[i]){ 40 d[y]=d[x]+val[i]; 41 q.push(make_pair(d[y],y)); 42 } 43 } 44 } 45 } 46 void dfs(int x,int fa){ 47 if(x==k){ 48 ans=min(ans,sum+f[fa][k+1]); 49 return; 50 } 51 for(int i=1;i<=k;i++){ 52 if(!vis[i]){ 53 vis[i]=1; 54 sum+=f[fa][i]; 55 dfs(x+1,i); 56 vis[i]=0; 57 sum-=f[fa][i]; 58 } 59 } 60 } 61 int main(){ 62 int u,v,w; 63 scanf("%d%d%d%d%d",&n,&m,&k,&S,&T); 64 flag[0]=S;flag[k+1]=T; 65 for(int i=1;i<=m;i++){ 66 scanf("%d%d%d",&u,&v,&w); 67 add(u,v,w); 68 } 69 for(int i=1;i<=k;i++){ 70 scanf("%d",&flag[i]); 71 } 72 for(int i=0;i<=k+1;i++){ 73 dijkstra(flag[i]); 74 for(int j=0;j<=k+1;j++){ 75 f[i][j]=d[flag[j]]; 76 } 77 } 78 dfs(0,0); 79 if(ans==INF){ 80 printf("-1\n"); 81 } 82 else{ 83 printf("%lld\n",ans); 84 } 85 return 0; 86 }