HDU 3605:Escape(最大流+状态压缩)
http://acm.hdu.edu.cn/showproblem.php?pid=3605
题意:有n个人要去到m个星球上,这n个人每个人对m个星球有一个选择,即愿不愿意去,“Y”or"N"。问是否可以全部人都顺利到自己想去的星球。
思路:很“有趣”的一道题目,n是1e5的大小,m只有10,没有想到状态压缩,看到n这么大肯定超时还是强行写了一波,于是RE(TLE)。想了挺久还是不会。看别人的思路是说二进制状态压缩。看到这就想到m只有10,于是可以分成1<<10 = 1024种情况,代表有这个选择,就相当于把人从1e5的大小强行压到1e3了。然后源点->选择->星球->汇点这样的图就建好了。源点->选择的边权是每种选择的人数,选择->星球的边权是对于每种选择,选择了这个星球的人数,星球->汇点的边权是星球容纳的人数。就酱了。Mark。
1 #include <cstdio> 2 #include <algorithm> 3 #include <iostream> 4 #include <cstring> 5 #include <string> 6 #include <cmath> 7 #include <queue> 8 #include <vector> 9 #include <map> 10 #include <set> 11 using namespace std; 12 #define INF 0x3f3f3f3f 13 #define N 1200 14 #define NUM 1024 15 typedef long long LL; 16 struct Edge { 17 int v, nxt, cap; 18 Edge () {} 19 Edge (int v, int nxt, int cap) : v(v), nxt(nxt), cap(cap) {} 20 }edge[N*N*2]; 21 int tot, head[N], cur[N], pre[N], dis[N], gap[N], S, T, tol[55]; 22 23 void Add(int u, int v, int cap) { 24 edge[tot] = Edge(v, head[u], cap); head[u] = tot++; 25 edge[tot] = Edge(u, head[v], 0); head[v] = tot++; 26 } 27 28 void BFS() { 29 memset(dis, -1, sizeof(dis)); 30 memset(gap, 0, sizeof(gap)); 31 queue<int> que; 32 while(!que.empty()) que.pop(); 33 dis[T] = 0; gap[0]++; que.push(T); 34 while(!que.empty()) { 35 int u = que.front(); que.pop(); 36 for(int i = head[u]; ~i; i = edge[i].nxt) { 37 Edge &e = edge[i]; 38 if(dis[e.v] == -1) continue; 39 dis[e.v] = dis[u] + 1; 40 que.push(e.v); 41 gap[dis[e.v]]++; 42 } 43 } 44 } 45 46 int ISAP(int n) { 47 BFS(); 48 memcpy(cur, head, sizeof(cur)); 49 int ans = 0, i, u = pre[S] = S; 50 while(dis[S] < n) { 51 if(u == T) { 52 int index, flow = INF; 53 for(i = S; i != T; i = edge[cur[i]].v) 54 if(flow > edge[cur[i]].cap) 55 flow = edge[cur[i]].cap, index = i; 56 for(i = S; i != T; i = edge[cur[i]].v) 57 edge[cur[i]].cap -= flow, edge[cur[i]^1].cap += flow; 58 u = index; 59 ans += flow; 60 } 61 // puts("AAAA"); 62 for(i = cur[u]; ~i; i = edge[i].nxt) 63 if(dis[edge[i].v] == dis[u] - 1 && edge[i].cap > 0) break; 64 // puts("BBBB"); 65 if(~i) { 66 cur[u] = i; pre[edge[i].v] = u; u = edge[i].v; 67 } else { 68 if(--gap[dis[u]] == 0) break; 69 int md = n; 70 for(i = head[u]; ~i; i = edge[i].nxt) 71 if(dis[edge[i].v] < md && edge[i].cap > 0) cur[u] = i, md = dis[edge[i].v]; 72 // puts("CCCC"); 73 ++gap[dis[u] = md + 1]; 74 // puts("ISAP"); 75 u = pre[u]; 76 } 77 } 78 return ans; 79 } 80 81 int main() { 82 int n, m; 83 while(~scanf("%d%d", &n, &m)) { 84 memset(head, -1, sizeof(head)); 85 tot = 0; S = NUM + m + 1, T = NUM + m + 2; 86 int a; int dp[N][15], s[N]; 87 memset(dp, 0, sizeof(dp)); 88 memset(s, 0, sizeof(s)); 89 for(int i = 1; i <= n; i++) { 90 int ss = 0; 91 for(int j = 1; j <= m; j++) { 92 scanf("%d", &a); 93 if(a) ss |= (a << (j - 1)); 94 } 95 s[ss]++; 96 for(int j = 1; j <= m; j++) { 97 if(ss & (1 << (j-1))) dp[ss][j]++; 98 } 99 } 100 for(int i = 1; i <= m; i++) scanf("%d", &tol[i]); 101 for(int i = 0; i <= 1024; i++) { 102 Add(S, i, s[i]); 103 for(int j = 1; j <= m; j++) { 104 if(dp[i][j]) { 105 Add(i, NUM + j, dp[i][j]); 106 } 107 } 108 } 109 for(int i = 1; i <= m; i++) Add(NUM + i, T, tol[i]); 110 int ans = ISAP(T + 1); 111 if(ans == n) puts("YES"); 112 else puts("NO"); 113 114 } 115 return 0; 116 }