首页 > 代码库 > [luoguP2774] 方格取数问题(最大点权独立集)

[luoguP2774] 方格取数问题(最大点权独立集)

传送门

 

引入两个概念:

最小点权覆盖集:满足每一条边的两个端点至少选一个的最小权点集。

最大点权独立集:满足每一条边的两个端点最多选一个的最大权点集。

现在对网格染色,使得相邻两点颜色不同,之后把两个颜色的点分成两个集合X,Y。S向X集合每个点连一条该点权值的边,Y集合每个点向T连一条该点权值的边,原来的边流量全部变为INF。这个网络的最小割为最小点权覆盖集。因为这个最小割满足了,对于中间每一条边,两端的点必定选择了一个。若一个都没有选择则S与T仍连通。且因为中间的边流量为INF所以不会是中间被堵塞。

然后我们可以证明对于每一个点权覆盖集,将选的点不选,不选的点选,得到的点集一定是一个点权独立集。因为每一条边至少选了一个,反选后就至少有一个选不了。

所以该网络的最小割=最大流=权值和-答案

答案就是权值和-最大流,跑一遍最大流即可

 

——代码

技术分享
  1 #include <queue>  2 #include <cstdio>  3 #include <cstring>  4 #include <iostream>  5 #define INF 1e9  6 #define N 10010  7 #define M 50001  8 #define min(x, y) ((x) < (y) ? (x) : (y))  9  10 int n, m, cnt, sum, s, t, num; 11 int head[N], to[M], val[M], next[M], dis[N], cur[N]; 12 int map[101][101], dx[4] = {0, 1, -1, 0}, dy[4] = {1, 0, 0, -1}; 13  14 inline int read() 15 { 16     int x = 0, f = 1; 17     char ch = getchar(); 18     for(; !isdigit(ch); ch = getchar()) if(ch == -) f = -1; 19     for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - 0; 20     return x * f; 21 } 22  23 inline void add(int x, int y, int z) 24 { 25     to[cnt] = y; 26     val[cnt] = z; 27     next[cnt] = head[x]; 28     head[x] = cnt++; 29 } 30  31 inline bool bfs() 32 { 33     int i, u, v; 34     std::queue <int> q; 35     memset(dis, -1, sizeof(dis)); 36     q.push(s); 37     dis[s] = 0; 38     while(!q.empty()) 39     { 40         u = q.front(), q.pop(); 41         for(i = head[u]; i ^ -1; i = next[i]) 42         { 43             v = to[i]; 44             if(val[i] && dis[v] == -1) 45             { 46                 dis[v] = dis[u] + 1; 47                 if(v == t) return 1; 48                 q.push(v); 49             } 50         } 51     } 52     return 0; 53 } 54  55 inline int dfs(int u, int maxflow) 56 { 57     if(u == t) return maxflow; 58     int v, d, ret = 0; 59     for(int &i = cur[u]; i ^ -1; i = next[i]) 60     { 61         v = to[i]; 62         if(val[i] && dis[v] == dis[u] + 1) 63         { 64             d = dfs(v, min(val[i], maxflow - ret)); 65             ret += d; 66             val[i] -= d; 67             val[i ^ 1] += d; 68             if(ret == maxflow) return ret; 69         } 70     } 71     if(ret ^ maxflow) dis[u] = -1; 72     return ret; 73 } 74  75 int main() 76 { 77     int i, j, k, x, y; 78     m = read(); 79     n = read(); 80     s = 0, t = n * m + 1; 81     memset(head, -1, sizeof(head)); 82     for(i = 1; i <= m; i++) 83         for(j = 1; j <= n; j++) 84         { 85             num++; 86             sum += x = read(); 87             if((i + j) & 1) 88             { 89                 add(s, num, x), add(num, s, 0); 90                 if(i > 1) add(num, num - n, INF), add(num - n, num, 0); 91                 if(i < m) add(num, num + n, INF), add(num + n, num, 0); 92                 if(j > 1) add(num, num - 1, INF), add(num - 1, num, 0); 93                 if(j < n) add(num, num + 1, INF), add(num + 1, num, 0); 94             } 95             else add(num, t, x), add(t, num, 0); 96         } 97     while(bfs()) 98     { 99         for(i = s; i <= t; i++) cur[i] = head[i];100         sum -= dfs(s, INF);101     }102     printf("%d\n", sum);103     return 0;104 }
View Code

 

[luoguP2774] 方格取数问题(最大点权独立集)