题目链接:
题目描述:
有n个人要迁移到m个星球,每个星球有最大容量,每个人有喜欢的星球,问是否所有的人都能迁移成功?
解题思路:
正常情况下建图,不会爆内存,但是TLE还是稳稳的。以前只遇到过网络流拆点建图,这个正好是缩点建图。吼吼吼~~~,建图的方式还是值得学习的。
因为星球数目最多十个,那么无论有多少个人,其不同选择也就2^10种咯。把不同的选择作为节点,节点就从10^5减少到了2^10,整整缩小了一个数量级呢。建立源点和汇点,源点和选择链接,边权为这种选择的出现次数;每种选择再与可到达的星球相连,边权为INF;星球与汇点相连,边权为星球的最大容量。然后跑最大流,判断是否满流即可。
1 #include <queue> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #include <algorithm> 6 #pragma comment (linker, "/STACK:1024000000,1024000000") 7 using namespace std; 8 9 const int maxn = 1024; 10 const int INF = 0x3f3f3f3f; 11 12 struct node 13 { 14 int to, next, w; 15 } edge[maxn*11*2+100]; 16 int head[maxn+100], Layer[maxn+100], Hash[maxn+100], tot; 17 18 void Add (int from, int to, int w) 19 { 20 edge[tot].to = to; 21 edge[tot].w = w; 22 edge[tot].next = head[from]; 23 head[from] = tot ++; 24 } 25 26 int Scan () 27 { 28 int res; 29 char ch; 30 res = 0; 31 32 while ((ch=getchar())<‘0‘ || ch>‘9‘); 33 34 if (ch>=‘0‘ && ch<=‘9‘) 35 res = ch - ‘0‘; 36 37 return res; 38 } 39 40 bool CountLayer (int s, int e) 41 { 42 memset (Layer, 0, sizeof(Layer)); 43 queue <int> Q; 44 Q.push (s); 45 Layer[s] = 1; 46 while (!Q.empty()) 47 { 48 int u = Q.front(); 49 Q.pop(); 50 for (int i=head[u]; i!=-1; i=edge[i].next) 51 { 52 int v = edge[i].to; 53 if (edge[i].w && !Layer[v]) 54 { 55 Layer[v] = Layer[u] + 1; 56 Q.push (v); 57 if (v == e) 58 return true; 59 } 60 } 61 } 62 return false; 63 } 64 65 int Dfs (int u, int e, int maxflow) 66 { 67 if (u == e) 68 return maxflow; 69 70 int uflow = 0; 71 for (int i=head[u]; i!=-1; i=edge[i].next) 72 { 73 int v = edge[i].to; 74 if (!edge[i].w || Layer[v] != Layer[u]+1) 75 continue; 76 77 int flow = min (maxflow-uflow, edge[i].w); 78 flow = Dfs (v, e, flow); 79 uflow += flow; 80 edge[i].w -= flow; 81 edge[i^1].w += flow; 82 if (maxflow == uflow) 83 break; 84 } 85 if (uflow == 0) 86 Layer[u] = 0; 87 return uflow; 88 } 89 90 int Dinic (int s, int e) 91 { 92 int maxflow = 0; 93 while (CountLayer (s, e)) 94 maxflow += Dfs (s, e, INF); 95 return maxflow; 96 } 97 98 int main () 99 { 100 int n, m, s, e, num; 101 while (scanf ("%d %d ", &n, &m) != EOF) 102 { 103 memset (head, -1, sizeof(head)); 104 memset (Hash, 0, sizeof(Hash)); 105 tot = s = 0; 106 e = (1<<10) + m + 1; 107 for (int i=1; i<=n; i++) 108 { 109 int y, x = 0; 110 for (int j=1; j<=m; j++) 111 { 112 int y = Scan(); 113 x = x*2 + y; 114 } 115 Hash[x] ++; 116 } 117 118 for (int i=0; i<maxn; i++) 119 { 120 Add (s, i+1, Hash[i]); 121 Add (i+1, s, 0); 122 for (int j=1; j<=m; j++) 123 if (i & 1<<(j-1)) 124 { 125 Add (i+1, maxn+j, INF); 126 Add (maxn+j, i+1, 0); 127 } 128 } 129 130 for (int i=1; i<=m; i++) 131 { 132 scanf ("%d", &num); 133 Add (maxn+i, e, num); 134 Add (e, maxn+i, 0); 135 } 136 137 int ans = Dinic (s, e); 138 printf ("%s\n", ans == n ? "YES" : "NO"); 139 } 140 return 0; 141 }
时间: 2024-10-28 20:24:03