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
",i,dp1[i]);
123         DP2();
124         int ans = solve();
125         printf("Case %d: ",ser);
126         if(ans == INF) printf("-1
");
127         else printf("%d
",ans);
128     }
129     return 0;
130 }
View Code

下面是标程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,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
",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
",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
", cas++, ans);
97     }
98     return 0;
99 }
View Code

标程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
",cc,ans);
150     }
151     return 0;
152 }
View Code
原文地址:https://www.cnblogs.com/allh123/p/3235342.html