[BZOJ4808] 马(最大独立集,最大流)
Posted tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ4808] 马(最大独立集,最大流)相关的知识,希望对你有一定的参考价值。
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4808
题意:其实就是找出一个点集的子集,使得这个子集中的点互不相连。求这个子集规模最大。
就是最大独立集。点好多,有200*200个。所以用dinic优化了下。
最大独立集=N-最大匹配,最大匹配=最大流,所以最大独立集=N-最大流。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 //下标从0开始 5 typedef struct Edge { 6 int u, v, w, next; 7 }Edge; 8 9 const int inf = 0x7f7f7f7f; 10 const int maxn = 400400; 11 const int maxm = 220; 12 13 int cnt, dhead[maxn]; 14 int cur[maxn], dd[maxn]; 15 Edge dedge[maxn<<1]; 16 // bool vis[maxn]; // 记录经过的点 17 int S, T, N; 18 19 void init() { 20 memset(dhead, -1, sizeof(dhead)); 21 for(int i = 0; i < maxn; i++) dedge[i].next = -1; 22 S = 0; cnt = 0; 23 } 24 25 void adde(int u, int v, int w, int c1=0) { 26 dedge[cnt].u = u; dedge[cnt].v = v; dedge[cnt].w = w; 27 dedge[cnt].next = dhead[u]; dhead[u] = cnt++; 28 dedge[cnt].u = v; dedge[cnt].v = u; dedge[cnt].w = c1; 29 dedge[cnt].next = dhead[v]; dhead[v] = cnt++; 30 } 31 32 bool bfs(int s, int t, int n) { 33 // memset(vis, 0, sizeof(vis)); 34 queue<int> q; 35 for(int i = 0; i < n; i++) dd[i] = inf; 36 dd[s] = 0; 37 q.push(s); 38 while(!q.empty()) { 39 int u = q.front(); q.pop(); 40 for(int i = dhead[u]; ~i; i = dedge[i].next) { 41 if(dd[dedge[i].v] > dd[u] + 1 && dedge[i].w > 0) { 42 dd[dedge[i].v] = dd[u] + 1; 43 // vis[dedge[i].v] = 1; 44 if(dedge[i].v == t) return 1; 45 q.push(dedge[i].v); 46 } 47 } 48 } 49 return 0; 50 } 51 52 int dinic(int s, int t, int n) { 53 int st[maxn], top; 54 int u; 55 int flow = 0; 56 while(bfs(s, t, n)) { 57 for(int i = 0; i < n; i++) cur[i] = dhead[i]; 58 u = s; top = 0; 59 while(cur[s] != -1) { 60 if(u == t) { 61 int tp = inf; 62 for(int i = top - 1; i >= 0; i--) { 63 tp = min(tp, dedge[st[i]].w); 64 } 65 flow += tp; 66 for(int i = top - 1; i >= 0; i--) { 67 dedge[st[i]].w -= tp; 68 dedge[st[i] ^ 1].w += tp; 69 if(dedge[st[i]].w == 0) top = i; 70 } 71 u = dedge[st[top]].u; 72 } 73 else if(cur[u] != -1 && dedge[cur[u]].w > 0 && dd[u] + 1 == dd[dedge[cur[u]].v]) { 74 st[top++] = cur[u]; 75 u = dedge[cur[u]].v; 76 } 77 else { 78 while(u != s && cur[u] == -1) { 79 u = dedge[st[--top]].u; 80 } 81 cur[u] = dedge[cur[u]].next; 82 } 83 } 84 } 85 return flow; 86 } 87 88 const int dx[11] = {-1,1,2,2,1,-1,-2,-2}; 89 const int dy[11] = {-2,-2,-1,1,2,2,1,-1}; 90 int n, m; 91 int mp[maxm][maxm]; 92 93 inline bool bound(int x, int y) { return x >= 1 && x <= n && y >= 1 && y <= m;} 94 inline int id(int x, int y) { return (x - 1) * m + y; } 95 96 int main() { 97 // freopen("in", "r", stdin); 98 while(~scanf("%d%d",&n,&m)) { 99 init(); 100 S = 0, T = 2 * id(n, m) + 1, N = T + 1; 101 for(int i = 1; i <= n; i++) { 102 for(int j = 1; j <= m; j++) { 103 adde(S, id(i,j), 1); 104 adde(id(n,m)+id(i,j), T, 1); 105 scanf("%d", &mp[i][j]); 106 } 107 } 108 int tot = 0; 109 for(int i = 1; i <= n; i++) { 110 for(int j = 1; j <= m; j++) { 111 if(mp[i][j] == 1) continue; 112 tot++; 113 for(int k = 0; k < 8; k++) { 114 int x = i + dx[k]; 115 int y = j + dy[k]; 116 if(!bound(x, y)) continue; 117 if(!mp[x][y]) adde(id(i,j), id(n,m)+id(x,y), inf); 118 } 119 } 120 } 121 printf("%d\n", tot - dinic(S, T, N)/2); 122 } 123 return 0; 124 }
以上是关于[BZOJ4808] 马(最大独立集,最大流)的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ-4808: 马 (二分图最大独立集 WAing~)
bzoj3175: [Tjoi2013]攻击装置&&4808: 马
bzoj4808: 马 & bzoj3175: [Tjoi2013]攻击装置 (黑白染色+最小割)