HDU 4640 状态压缩DP 未写完
原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=4640
解题思路:
首先用一个简单的2^n*n的dp可以求出一个人访问一个给定状态的最小花费,因为这i个人是等价的,所以用dp[i][mask]表示i个人跑完mask这个状态的最小花费,所以首先枚举集合mask,对于dp[i][mask],枚举mask的子集v,dp[i][mask]可以由dp[1][v],dp[i-1][mask^v]转移过来,注意这里用来合并的集合是不能有重复的,这个类似背包……这样就可以算出对于每个状态三个人访问完的最小花费,之后对于给定的需要访问的状态,枚举包含这个给定状态的集合更新答案就可以了……注意对于刚开始给定的图是不能floyd的,因为要求任意两个人的路径不能相交……还有就是1这个节点可以每个人经过多次,这里需要特殊处理一下……
以上摘自杭电的解题报告
下面是我还未写完的代码,我还不会做这个题,所以···还得想想····以后会改好的
1 #include <cstdio> 2 #include <queue> 3 using namespace std; 4 #define N (1<<17)+5 5 #define INF 100000000 6 #define min(a,b) a<b?a:b 7 #define max(a,b) a>b?a:b 8 9 int n,status; //人数,学妹位置的状态 10 int d[N][20],dp1[N],dp2[N]; 11 bool in[N][20]; 12 int edge[20][20]; 13 queue<int> qu; 14 void initScan() 15 { 16 int m; 17 scanf("%d%d",&n,&m); 18 for(int i=0; i<n; ++i) 19 { 20 for(int j=0; j<n; ++j) 21 { 22 if(i == j) edge[i][j] = 0; 23 else edge[i][j] = INF; 24 } 25 } 26 while(m--) 27 { 28 int u,v,c; 29 scanf("%d%d%d",&u,&v,&c); 30 --u,--v; 31 edge[u][v] = min(edge[u][v],c); 32 edge[v][u] = edge[u][v]; 33 } 34 int k; 35 status = 0; 36 scanf("%d",&k); 37 while(k--) 38 { 39 int sis; 40 scanf("%d",&sis); 41 status |= (1<<(sis-1)); 42 } 43 status >>= 1; 44 } 45 void bfs() 46 { 47 memset(in,0,sizeof(in)); 48 memset(d,0x3f,sizeof(d)); 49 qu.push(0);//先城市 50 qu.push(1);//后状态 51 d[1][0] = 0; 52 in[1][0] = true; 53 while(!qu.empty()) 54 { 55 int i = qu.front();//状态 56 qu.pop(); 57 int j = qu.front();//城市 58 qu.pop(); 59 in[i][j] = false; 60 for(int k=1; k<n; ++k) 61 { 62 int w = i |(1 << k); 63 if(d[w][k] > d[i][j] + edge[j][k] ) 64 { 65 d[w][k] = d[i][j] + edge[j][k]; 66 if(!d[w][k]) 67 { 68 qu.push(k); 69 qu.push(w); 70 in[w][k] = 1; 71 } 72 } 73 } 74 } 75 } 76 void DP1() 77 { 78 memset(dp1,0x3f,sizeof(dp1)); 79 for(int i=1; i<(1<<n); ++i) 80 { 81 for(int j=0; j<n; ++j) 82 dp1[i>>1] = min(dp1[i>>1],d[i][j]); 83 } 84 } 85 void DP2() 86 { 87 for(int i=1; i<(1<<n); ++i) 88 { 89 int j = i; 90 while(j) 91 { 92 j=(j-1)&i; 93 dp2[i] = min( dp2[i],max(dp2[j],dp2[i^j]) ); 94 } 95 } 96 } 97 int solve() 98 { 99 int ans = INF; 100 int j = status; 101 while(j) 102 { 103 j=(j-1)&status; 104 ans = min( ans,max(dp2[j],dp1[status^j]) ); 105 ans = min(ans,max(dp2[status^j],dp1[j]) ); 106 } 107 return ans; 108 } 109 110 int main() 111 { 112 freopen("in.cpp","r",stdin); 113 freopen("myout.cpp","w",stdout); 114 int t; 115 scanf("%d",&t); 116 for(int ser=1; ser<=t; ++ser) 117 { 118 initScan(); 119 bfs(); 120 DP1(); 121 for(int i=0; i<(1<<n); ++i) 122 printf("d[%d] = %d\n",i,dp1[i]); 123 DP2(); 124 int ans = solve(); 125 printf("Case %d: ",ser); 126 if(ans == INF) printf("-1\n"); 127 else printf("%d\n",ans); 128 } 129 return 0; 130 }
下面是标程1:
1 #include<stdio.h> 2 #include<algorithm> 3 #include<string.h> 4 #include<vector> 5 #include<queue> 6 using namespace std; 7 #define INF 0x3f3f3f3f 8 #define N 101 9 int sta; 10 int d[N][N]; 11 int dp[1 << 17][17]; 12 bool in[1 << 17][17]; 13 int dp_1[1 << 16], dp_2[1 << 16]; 14 int main() { 15 int t, cas = 1; 16 scanf(" %d", &t); 17 while (t--) { 18 int n, m; 19 scanf(" %d %d", &n, &m); 20 // if(cas==13) printf("%d %d\n",n,m); 21 memset(d, 0x3f, sizeof(d)); 22 for (int i = 0; i < m; i++) { 23 int x, y, s; 24 scanf(" %d %d %d", &x, &y, &s); 25 // if(cas==13) printf("%d %d %d\n",x,y,s); 26 d[x][y] = min(d[x][y], s); 27 d[y][x] = d[x][y]; 28 } 29 30 queue<int> qu; 31 qu.push(1); 32 qu.push(0); 33 memset(in, 0, sizeof(in)); 34 memset(dp, 0x3f, sizeof(dp)); 35 dp[1][0] = 0; 36 in[1][0] = true; 37 38 while (!qu.empty()) { 39 int s_sta = qu.front(); 40 qu.pop(); 41 int s = qu.front() + 1; 42 qu.pop(); 43 in[s_sta][s - 1] = false; 44 45 for (int i = 0; i < n; i++) { 46 int to = i + 1; 47 int t_sta = (1 << i) | s_sta; 48 if (to == 1) 49 continue; 50 if (dp[t_sta][to - 1] > dp[s_sta][s - 1] + d[s][to]) { 51 dp[t_sta][to - 1] = dp[s_sta][s - 1] + d[s][to]; 52 if (!in[t_sta][to - 1]) { 53 in[t_sta][to - 1] = 1; 54 qu.push(t_sta); 55 qu.push(to - 1); 56 } 57 } 58 } 59 } 60 61 memset(dp_1, 0x3f, sizeof(dp_1)); 62 for (int i = 1; i < (1 << n); i++) { 63 for (int j = 0; j < n; j++) { 64 dp_1[i >> 1] = min(dp_1[i >> 1], dp[i][j]); 65 } 66 } 67 68 int tar = 0, k; 69 scanf(" %d", &k); 70 // if(cas==13) printf("%d\n",k); 71 while (k--) { 72 int x; 73 scanf(" %d", &x); 74 // if(cas==13) printf("%d ",x); 75 tar |= (1 << (x - 2)); 76 } 77 int ans = INF; 78 int tol = (1 << (n - 1)) - 1; 79 memcpy(dp_2, dp_1, sizeof(dp_1)); 80 for (int i = 1; i < (1 << (n - 1)); i++) { 81 for (int j = i; j; j = (j - 1) & i) { 82 dp_2[i] = min(dp_2[i], max(dp_1[j], dp_1[i ^ j])); 83 } 84 } 85 for (int i = tol; i; i--) { 86 for (int j = i;; j = (j - 1) & i) { 87 if ((i & tar) == tar) { 88 ans = min(ans, max(dp_1[j], dp_2[i ^ j])); 89 } 90 if (j == 0) 91 break; 92 } 93 } 94 if (ans == INF) 95 ans = -1; 96 printf("Case %d: %d\n", cas++, ans); 97 } 98 return 0; 99 }
标程2:
1 #include<stdio.h> 2 #include<string.h> 3 #include<math.h> 4 #include<iostream> 5 #include<algorithm> 6 #include<map> 7 #include<set> 8 #include<vector> 9 using namespace std; 10 typedef __int64 lld; 11 #define pb push_back 12 #define mp make_pair 13 #define X first 14 #define Y second 15 #define maxn 20 16 struct Edge 17 { 18 int v,s,next; 19 }edge[1000010]; 20 int head[maxn]; 21 int pos; 22 void insert(int x,int y,int s) 23 { 24 edge[pos].v=y; 25 edge[pos].s=s; 26 edge[pos].next=head[x]; 27 head[x]=pos++; 28 } 29 int dis[1<<16][16]; 30 bool vis[1<<16][16]; 31 pair<int,int>queue[2000010]; 32 int rear,front; 33 int maxQ=2000010; 34 int dp[1<<16]; 35 int f[1<<16]; 36 int main() 37 { 38 // freopen("input.txt","r",stdin); 39 int cas; 40 scanf("%d",&cas); 41 for(int cc=1;cc<=cas;cc++) 42 { 43 int n,m; 44 scanf("%d %d",&n,&m); 45 memset(head,0,sizeof(head)); 46 pos=1; 47 while(m--) 48 { 49 int x,y,s; 50 scanf("%d %d %d",&x,&y,&s); 51 insert(x,y,s); 52 insert(y,x,s); 53 } 54 memset(dis,-1,sizeof(dis)); 55 memset(vis,false,sizeof(vis)); 56 rear=front=0; 57 for(int i=head[1];i;i=edge[i].next) 58 { 59 int v=edge[i].v; 60 v-=2; 61 if(dis[1<<v][v] == -1 || edge[i].s < dis[1<<v][v]) 62 { 63 dis[1<<v][v]=edge[i].s; 64 if(!vis[1<<v][v]) 65 { 66 vis[1<<v][v]=true; 67 queue[front++]=mp(1<<v,v); 68 } 69 } 70 } 71 while(rear != front) 72 { 73 int mask=queue[rear].X; 74 int u=queue[rear].Y; 75 rear++; 76 if(rear == maxQ) 77 rear=0; 78 vis[mask][u]=false; 79 for(int i=head[u+2];i;i=edge[i].next) 80 { 81 int v=edge[i].v; 82 if(v == 1) 83 continue; 84 v-=2; 85 int next=mask|(1<<v); 86 if(dis[next][v] == -1 || dis[mask][u]+edge[i].s < dis[next][v]) 87 { 88 dis[next][v]=dis[mask][u]+edge[i].s; 89 if(!vis[next][v]) 90 { 91 vis[next][v]=true; 92 queue[front++]=mp(next,v); 93 if(front == maxQ) 94 front=0; 95 } 96 } 97 } 98 } 99 memset(dp,-1,sizeof(dp)); 100 dp[0]=0; 101 int T=1<<(n-1); 102 for(int mask=1;mask<T;mask++) 103 for(int i=0;i<n-1;i++) 104 { 105 if(dis[mask][i] == -1) 106 continue; 107 if(dp[mask] == -1 || dis[mask][i] < dp[mask]) 108 dp[mask]=dis[mask][i]; 109 } 110 for(int mask=0;mask<T;mask++) 111 f[mask]=dp[mask]; 112 for(int k=0;k<2;k++) 113 { 114 for(int u=T-1;u>0;u--) 115 for(int v1=u;;v1=(v1-1)&u) 116 { 117 int v2=u^v1; 118 if(dp[v1] == -1 || f[v2] == -1) 119 { 120 if(v1 == 0) 121 break; 122 continue; 123 } 124 if(dp[u] == -1 || max(dp[v1],f[v2]) < dp[u]) 125 dp[u]=max(dp[v1],f[v2]); 126 if(v1 == 0) 127 break; 128 } 129 } 130 int Q; 131 scanf("%d",&Q); 132 int mask=0; 133 while(Q--) 134 { 135 int x; 136 scanf("%d",&x); 137 x-=2; 138 mask|=1<<x; 139 } 140 int ans=-1; 141 for(int u=0;u<T;u++) 142 if((u&mask) == mask) 143 { 144 if(dp[u] == -1) 145 continue; 146 if(ans == -1 || dp[u] < ans) 147 ans=dp[u]; 148 } 149 printf("Case %d: %d\n",cc,ans); 150 } 151 return 0; 152 }