題目鏈接
題意
一共有n個點,m個邊,現在一個人要去其中的r個地點R1,R2,R3,R4…Rr(不一定按照這個順序)他可以坐飛機去第一個點,然後坐飛機從最後一個點返回,剩下的點只能走路,讓我們求出“經過這r個點的最短路程”
這個題我坑了,剛開始沒有想到可以從任意一個點出發。一直以爲題意是必須從第一個點出發,所以把dfs()裏面的for(int i=1;i<=r;i++)寫成了for(int i=2;i<=r;i++),後來想到可以從任意一個路徑出發的時候,這裏忘了改過去了
/(ㄒoㄒ)/~~自作聰明圖省事啊…
解決
- 跑一遍floyd,求出多源最短路徑
- 枚舉起點,深搜即可(由於r<=8,所以深搜的深度並不會很深)
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<(b);++i)
const int INF = 0x3f3f3f3f;
bool vis[10];
int ans=INF;
int n,m,r;
int R[10];
int d[205][205];
void dfs(int x,int cur) //x是地點編號,cur是已經走過的距離
{
bool flag = 1;
for(int i=1;i<=r;i++) if(!vis[R[i]]) flag=0 ;
if(flag&&cur<ans){ //已經經過了所有的r個點
ans=cur;
return;
}
for(int i=1;i<=r;i++){
if(vis[R[i]]) continue;
if(d[x][R[i]]>=INF) continue;
vis[R[i]]=true;
dfs(R[i],cur+d[x][R[i]]);
vis[R[i]]=false;
}
return ;
}
int main()
{
scanf("%d%d%d",&n,&m,&r);
rep(i,1,r+1) scanf("%d",&R[i]);
for(int i=0;i<205;i++) for(int j=0;j<205;j++) {
if(i==j) d[i][j]=0;
else d[i][j]=INF;
}
rep(i,0,m){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
d[u][v]=w; //bidirectional雙向邊
d[v][u]=w;
}
for(int k=1;k<=n;k++) //floyd
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
d[i][j] = min(d[i][j],d[i][k]+d[k][j]);
memset(vis,0,sizeof(vis));
for(int i=1;i<=r;i++){ //枚舉起點
vis[R[i]]=true;
dfs(R[i],0);
vis[R[i]]=false;
}
printf("%d\n",ans);
}