题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4640
思路:f[i][j]表示一个人状态i下走到j的最小花费,dp[i][j]表示i个人在状态j下的最下花费。首先我们可以一遍bfs求出f[i][j],然后通过f[i][j]得到dp[1][i],最后就是更新dp[i][j]了。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 #define inf 1<<30 8 typedef pair<int,int>PP; 9 10 int map[20][20]; 11 int f[1<<18][20];//派一个人去,在某状态下到达点v的最小花费 12 int dp[4][1<<18];//派i个人去,在某状态的最小花费 13 bool mark[1<<18][20]; 14 int n,m,S,ans; 15 16 void bfs() 17 { 18 queue<PP>que; 19 que.push(make_pair(0,0)); 20 memset(mark,false,sizeof(mark)); 21 for(int i=0;i<(1<<n);i++) 22 for(int j=0;j<n;j++)f[i][j]=inf; 23 f[0][0]=0; 24 while(!que.empty()){ 25 PP p=que.front(); 26 que.pop(); 27 int s=p.first,u=p.second; 28 mark[s][u]=false; 29 for(int i=0;i<n;i++){ 30 if(map[u][i]<inf&&f[s|(1<<i)][i]>f[s][u]+map[u][i]){ 31 f[s|(1<<i)][i]=f[s][u]+map[u][i]; 32 if(!mark[s|(1<<i)][i]){ 33 mark[s|(1<<i)][i]=true; 34 que.push(make_pair(s|(1<<i),i)); 35 } 36 } 37 } 38 } 39 } 40 41 void Solve() 42 { 43 for(int i=1;i<=3;i++) 44 for(int j=0;j<(1<<n);j++)dp[i][j]=inf; 45 for(int i=0;i<(1<<n);i++) 46 for(int j=0;j<n;j++)dp[1][i]=min(dp[1][i],f[i][j]); 47 for(int i=2;i<=3;i++){ 48 for(int j=0;j<(1<<n);j++){ 49 //枚举子集 50 for(int k=j;k;k=(k-1)&j){ 51 dp[i][j]=min(dp[i][j],max(dp[1][k|1],dp[i-1][(j^k)|1])); 52 } 53 } 54 } 55 ans=inf; 56 for(int i=1;i<=3;i++) 57 for(int j=0;j<(1<<n);j++)if((j&S)==S)ans=min(ans,dp[i][j]); 58 if(ans==inf)ans=-1; 59 printf("%d ",ans); 60 } 61 62 int main() 63 { 64 int _case,u,v,w,k,t=1; 65 scanf("%d",&_case); 66 while(_case--){ 67 scanf("%d%d",&n,&m); 68 for(int i=0;i<=n;i++) 69 for(int j=0;j<=n;j++)map[i][j]=(i==j?0:inf); 70 while(m--){ 71 scanf("%d%d%d",&u,&v,&w); 72 u--,v--; 73 map[u][v]=map[v][u]=min(map[u][v],w); 74 } 75 S=0; 76 scanf("%d",&k); 77 while(k--){ 78 scanf("%d",&u); 79 u--; 80 S|=(1<<u); 81 } 82 bfs(); 83 printf("Case %d: ",t++); 84 Solve(); 85 } 86 return 0; 87 } 88 89 90 91