题意:一个acm队伍,三个人,然后有个n(最多17个)个岛组成的地方,有m条路把这些岛联系在一起,每个路有个权值,表示时间。然后三个人从1点出发,分别到这些岛上去,三个人去的地方不能交叉,也就是说一个人去过该点,另一个人就不能在这个点过了。如果有个点去不了那么就输出-1.然后输出最短的时间。
思路:对这17个岛用二进制表示。
设
int f[1<<18][20];//1个人 i状态走到j的最小值
int dp[4][1<<18];//i个人 状态j 的最小值
那么利用spfa求最短路,存入f中。
然后再枚举2个人,3个人的情况求dp;
dp[i][mask]表示i个人在状态mask下的最小值,那么枚举mask的子集v,前者就可以由dp[1][v]+dp[i-1][mask^v]得来,
设s是最终的状态,然后枚举mask,当mask包含s时,算一次最小值即可。
http://www.cnblogs.com/wally/p/3330414.html
代码是网上大牛的,厚着脸搞过来:
http://www.cnblogs.com/wally/p/3330414.html
代码是网上大牛的,厚着脸搞过来:
#include <iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define inf 1<<30
using namespace std;
typedef pair<int,int> pp;
int map[20][20],n,m,s,ans;
int f[1<<18][20];//1个人 i状态走到j min
int dp[4][1<<18];//i个人 状态j min
bool mark[1<<18][20];//用来标记i状态走到了j
void bfs()
{
queue<pp>que;
que.push(make_pair(0,0));
memset(mark,false,sizeof(mark));
for(int i=0; i<(1<<n); i++)
for(int j=0; j<n; j++)
f[i][j]=inf;
f[0][0]=0;
while(!que.empty())
{
pp tmp=que.front();
que.pop();
int st=tmp.first,ed=tmp.second;
mark[st][ed]=false;
for(int i=0; i<n; i++)
{
if(map[ed][i]<inf&&f[st|(1<<i)][i]>f[st][ed]+map[ed][i])
{
f[st|(1<<i)][i]=f[st][ed]+map[ed][i];
if(!mark[st|(1<<i)][i])
{
mark[st|(1<<i)][i]=true;
que.push(make_pair(st|(1<<i),i));
}
}
}
}
}
void solve()
{
for(int i=1; i<=3; i++)
for(int j=0; j<(1<<n); j++)
dp[i][j]=inf;
for(int i=0; i<(1<<n); i++)
for(int j=0; j<n; j++)
dp[1][i]=min(dp[1][i],f[i][j]);//只要看i就可以,i表示到过哪些地方,j只是表示终点在哪里
for(int i=2; i<=3; i++)//枚举人数
for(int j=0; j<(1<<n); j++)//这些个状态
for(int k=j; k; k=(k-1)&j) //枚举子集
dp[i][j]=min(dp[i][j],max(dp[1][k],dp[i-1][(j^k)]));
ans=inf;
for(int i=1; i<=3; i++)
for(int j=0; j<(1<<n); j++)
if((j&s)==s)//看s是否是j的子集,包括s本身,因为j如果去得地方更多反而时间更短也有可能,注意。
ans=min(ans,dp[i][j]);
ans=ans==inf?-1:ans;
printf("%d\n",ans);
}
int main()
{
//freopen("in.txt","r",stdin);
int t,cas,i,j,k,u,v,w;
scanf("%d",&t);
for(cas=1; cas<=t; cas++)
{
scanf("%d%d",&n,&m);
for(i=0; i<=n; i++) for(j=0; j<=n; j++) map[i][j]=i==j?0:inf;
while(m--)
{
scanf("%d%d%d",&u,&v,&w);
--u;
--v;
map[u][v]=map[v][u]=min(map[u][v],w);
}
s=0;
scanf("%d",&k);
while(k--)
{
scanf("%d",&u);
s|=(1<<(u-1));
}
bfs();
printf("Case %d: ",cas);
solve();
}
return 0;
}