hdu 1569 方格取数(2) 最大点权独立集
方格取数(2)
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 5425 Accepted Submission(s): 1695
Problem Description
给你一个m*n的格子的棋盘,每个格子里面有一个非负数。
从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大。
从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大。
Input
包括多个测试实例,每个测试实例包括2整数m,n和m*n个非负数(m<=50,n<=50)
Output
对于每个测试实例,输出可能取得的最大的和
Sample Input
3 3
75 15 21
75 15 28
34 70 5
Sample Output
188
题意就是求最大点权独立集。
点覆盖集:是无向图G点一个点集,使得该图中所有边都至少有一个端点在该集合内。
点独立集:是无向图的一个点集,使得任两个在该集合中的点在原图中都不相邻。
最小点覆盖集(minimum vertex covering set,MinVCS)是在无向图中,点数最少的点覆盖集。
最大点独立集(maximum vertex independent set,MaxVIS)是在无向图中,点数最多的点独立集。
以上两个问题在二分图中都可以用最大匹配模型来快速解决。
更为一般的问题:
最小点权覆盖集(minimum weight vertex covering set,MinWVCS)是在带点权无向图G中,点权之和最小的点覆盖集。
最大点权独立集(maximum weight vertex independent set,MaxWVIS)是在带点权无向图中,点权之和最大的点独立集。
最小点权覆盖问题建图方法:
在原图点基础上增加源点s和汇点t。讲二分图中每条边替换为容量为正无穷点有向边。
添加s到X集合中点的有向边,容量为该点的权值。添加集合Y中的点到t的有向边,容量为该点的权值。然后求最小割。
最大点独立集 = 全集 - 最小点覆盖集
最大点权独立集 = 全集 - 最小点权覆盖集
最大点权独立集点权之和 = 所有点权之和 - 最小点权覆盖集点权之和
所以此题求最大点权独立集 就是全集 - 最小点权覆盖集。
那么把方格中的点分为两个部分X和Y。
增加源点s和汇点t。X和Y点边即X中的点与其相邻点Y中的点连接一条有向边。
s到X点边为每个点的权值。Y到t点边为每个点的权值。X到Y的边容量为正无穷。
可以这样考虑,因为X中的点连到和它相邻的Y中的点的边都是题目中不允许点。
所以相当于选出这样的非法边,然后去掉最小点。那么剩下来就是最大点。
bzoj1324 Exca王者之剑和这题类似
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | #include <bits/stdc++.h> using namespace std; #define maxn 55 const int inf = 0x3f3f3f3f; int M, N; int mp[maxn][maxn]; int mark[maxn][maxn]; int dir[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; struct Edge { int from, to, cap, flow; Edge( int f, int t, int c, int fl) { from = f; to = t; cap = c; flow = fl; } }; vector <Edge> edges; vector < int > G[maxn*maxn]; int s, t, n, m; int cur[maxn*maxn], vis[maxn*maxn], d[maxn*maxn]; void AddEdge( int from, int to, int cap) { edges.push_back(Edge(from, to, cap, 0)); edges.push_back(Edge(to, from, 0, 0)); m = edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool bfs() { memset (vis, 0, sizeof (vis)); d[s] = 0; vis[s] = 1; queue < int > q; q.push(s); while (!q.empty()) { int u = q.front(); q.pop(); for ( int i = 0; i < G[u].size(); i++) { Edge &e = edges[G[u][i]]; if (!vis[e.to] && e.cap > e.flow) { vis[e.to] = 1; d[e.to] = d[u]+1; q.push(e.to); } } } return vis[t]; } int dfs( int x, int a) { if (x == t || a == 0) return a; int flow = 0, f; for ( int &i = cur[x]; i < G[x].size(); i++) { Edge &e = edges[G[x][i]]; if (d[x]+1 == d[e.to] && (f = dfs(e.to, min(a, e.cap-e.flow))) > 0) { e.flow += f; edges[G[x][i]^1].flow -= f; flow += f; a -= f; if (a == 0) break ; } } return flow; } int Maxflow() { int flow = 0; while (bfs()) { memset (cur, 0, sizeof (cur)); flow += dfs(s, inf); } return flow; } bool judge( int x, int y) { if (x >= 1 && x <= N && y >= 1 && y <= M) return true ; return false ; } int main() { while (~ scanf ( "%d%d" , &N, &M)) { edges.clear(); for ( int i = 0; i < maxn*maxn; i++) G[i].clear(); int sum = 0; for ( int i = 1; i <= N; i++) { for ( int j = 1; j <= M; j++) { scanf ( "%d" , &mp[i][j]); sum += mp[i][j]; } } s = 0; t = N*M+1; for ( int i = 1; i <= N; i++) { for ( int j = 1; j <= M; j++) { if ((i+j)%2 == 0) { AddEdge(s, (i-1)*M+j, mp[i][j]); if (i > 1) AddEdge((i-1)*M+j, (i-2)*M+j, inf); if (j > 1) AddEdge((i-1)*M+j, (i-1)*M+j-1, inf); if (i < N) AddEdge((i-1)*M+j, i*M+j, inf); if (j < M) AddEdge((i-1)*M+j, (i-1)*M+j+1, inf); } else AddEdge((i-1)*M+j, t, mp[i][j]); } } printf ( "%d\n" , sum - Maxflow()); } } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步