LightOJ1316 A Wedding Party(状压DP)
这题事实上只需要关心15个商店和一个起点一个终点,预处理出这几个点之间的最短距离。Floyd会超时,用Dijkstra即可。
然后就是dp[u][S]表示已经经过商店集合S且当前在第u个商店所花的最少时间。
最后的结果是找到所有dp[u][S]有解且u能到达终点的最大的|S|,而最短时间就是dp[u][S]+dist[u][vt]。
细节还挺多的。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define INF (1<<29) 6 7 int d[15][1<<15]; 8 int G[555][555],dist[555][555],shop[15]; 9 void dijkstra(int vs,int n){ 10 for(int i=0; i<n; ++i) dist[vs][i]=INF; 11 dist[vs][vs]=0; 12 bool vis[555]={0}; 13 for(int i=0; i<n; ++i){ 14 int u=-1,mm=INF; 15 for(int v=0; v<n; ++v){ 16 if(!vis[v] && mm>dist[vs][v]){ 17 mm=dist[vs][v]; 18 u=v; 19 } 20 } 21 if(u==-1) break; 22 vis[u]=1; 23 for(int v=0; v<n; ++v){ 24 if(!vis[v] && G[u][v]!=INF && dist[vs][v]>dist[vs][u]+G[u][v]){ 25 dist[vs][v]=dist[vs][u]+G[u][v]; 26 } 27 } 28 } 29 } 30 int getCnt(int s){ 31 int res=0; 32 for(int i=0; i<15; ++i){ 33 if((s>>i)&1) ++res; 34 } 35 return res; 36 } 37 int cnt[1<<15]; 38 int main(){ 39 for(int i=0; i<(1<<15); ++i) cnt[i]=getCnt(i); 40 int t,n,m,s,a,b,c; 41 scanf("%d",&t); 42 for(int cse=1; cse<=t; ++cse){ 43 scanf("%d%d%d",&n,&m,&s); 44 for(int i=0; i<n; ++i){ 45 for(int j=0; j<n; ++j) G[i][j]=INF; 46 } 47 for(int i=0; i<s; ++i) scanf("%d",&shop[i]); 48 while(m--){ 49 scanf("%d%d%d",&a,&b,&c); 50 G[a][b]=min(G[a][b],c); 51 } 52 dijkstra(0,n); 53 for(int i=0; i<s; ++i) dijkstra(shop[i],n); 54 55 if(dist[0][n-1]==INF){ 56 printf("Case %d: Impossible\n",cse); 57 continue; 58 } 59 60 for(int i=0; i<s; ++i){ 61 for(int j=0; j<(1<<s); ++j) d[i][j]=INF; 62 } 63 for(int i=0; i<s; ++i){ 64 d[i][1<<i]=dist[0][shop[i]]; 65 } 66 for(int i=1; i<(1<<s); ++i){ 67 for(int j=0; j<s; ++j){ 68 if(((i>>j)&1)==0) continue; 69 for(int k=0; k<s; ++k){ 70 if(k==j || ((i>>k)&1)==0) continue; 71 d[j][i]=min(d[j][i],d[k][i^(1<<j)]+dist[shop[k]][shop[j]]); 72 } 73 } 74 } 75 int mx=0,mm=INF; 76 for(int i=1; i<(1<<s); ++i){ 77 for(int j=0; j<s; ++j){ 78 if(d[j][i]==INF || dist[shop[j]][n-1]==INF) continue; 79 mx=max(mx,cnt[i]); 80 } 81 } 82 for(int i=1; i<(1<<s); ++i){ 83 for(int j=0; j<s; ++j){ 84 if(d[j][i]==INF) continue; 85 if(cnt[i]==mx) mm=min(mm,d[j][i]+dist[shop[j]][n-1]); 86 } 87 } 88 if(mm!=INF) printf("Case %d: %d %d\n",cse,mx,mm); 89 else printf("Case %d: 0 %d\n",cse,dist[0][n-1]); 90 } 91 return 0; 92 }