HDU 1565:方格取数(1)(最大点权独立集)***

http://acm.hdu.edu.cn/showproblem.php?pid=1565

题意:中文。

思路:一个棋盘,要使得相邻的点不能同时选,问最大和是多少,这个问题就是最大点权独立集。

可以转化为所有的点权 - 最小点权覆盖集(最小割) = 最大点权独立集。

转载两个的定义:这里

覆盖集(vertex covering set,VCS)是无向图的一个点集,使得该图中所有边都至少有一个端点在该集合内。形式化的定义是点覆盖集为G‘VV∈(,)uvE∀∈,满足对于,都有 或成立,即,‘uV∈‘vV∈‘uV∈‘vV∈至少一个成立。形象地说是若干个点“覆盖”住了 与它们邻接的边,这些边恰好组成了原边集。

点独立集(vertex independent set,VIS)是无向图的一个点集,使得任两个在该集合中的点在原图中都不相邻。或者说是导出子图为零图(没有边)的点集。形式化的定义是点独立集为,满足对于,都有G‘VV∈,‘uvV∀∈(,)uvE∉成立。点独立集还有一种等价的定义:点独立集为,满足对于,都有‘VV∈‘uV∈‘vV∈(,)uvE∀∈与不同时成立。

从覆盖集的定义可以看出,求覆盖集就是求最小割(最大流),这个最小点权覆盖集不是S集合就是T集合,最大权独立集就是最小点权覆盖集的补集。

因此把棋盘通过黑白染色:

设一种颜色和S相连(容量为点权),然后用这种颜色去连接相邻另一种颜色(容量为INF),另一种颜色和T相连(容量为点权)。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <queue>
 4 using namespace std;
 5 #define N 510
 6 #define INF 0x3f3f3f3f
 7 typedef long long LL;
 8 struct Edge {
 9     int v, nxt, cap;
10     Edge () {}
11     Edge (int v, int nxt, int cap) : v(v), nxt(nxt), cap(cap) {}
12 } edge[N*N];
13 int head[N], tot, dis[N], cur[N], pre[N], gap[N], n, mp[25][25], dx[] = {0, 0, 1, -1}, dy[] = {1, -1, 0, 0};
14
15 bool check(int x, int y) {
16     if(1 <= x && x <= n && 1 <= y && y <= n) return true;
17     return false;
18 }
19
20 void Add(int u, int v, int cap) {
21     edge[tot] = Edge(v, head[u], cap); head[u] = tot++;
22     edge[tot] = Edge(u, head[v], 0); head[v] = tot++;
23 }
24
25 int BFS(int S, int T) {
26     queue<int> que; que.push(T);
27     memset(dis, INF, sizeof(dis));
28     memset(gap, 0, sizeof(gap));
29     gap[0]++; dis[T] = 0;
30     while(!que.empty()) {
31         int u = que.front(); que.pop();
32         for(int i = head[u]; ~i; i = edge[i].nxt) {
33             int v = edge[i].v;
34             if(dis[v] == INF) {
35                 dis[v] = dis[u] + 1;
36                 gap[dis[v]]++;
37                 que.push(v);
38             }
39         }
40     }
41 }
42
43 LL ISAP(int S, int T, int n) {
44     BFS(S, T);
45     memcpy(cur, head, sizeof(cur));
46     int u = pre[S] = S, i, index, flow; LL ans = 0;
47     while(dis[S] < n) {
48         if(u == T) {
49             flow = INF, index = S; // index = S !!!
50             for(i = S; i != T; i = edge[cur[i]].v)
51                 if(flow > edge[cur[i]].cap) flow = edge[cur[i]].cap, index = i;
52             for(i = S; i != T; i = edge[cur[i]].v)
53                 edge[cur[i]].cap -= flow, edge[cur[i]^1].cap += flow;
54             ans += flow, u = index;
55         }
56         for(i = cur[u]; ~i; i = edge[i].nxt)
57             if(edge[i].cap > 0 && dis[edge[i].v] == dis[u] - 1) break;
58         if(~i) {
59             pre[edge[i].v] = u; cur[u] = i; u = edge[i].v;
60         } else {
61             if(--gap[dis[u]] == 0) break;
62             int md = n;
63             for(i = head[u]; ~i; i = edge[i].nxt)
64                 if(md > dis[edge[i].v] && edge[i].cap > 0) md = dis[edge[i].v], cur[u] = i;
65             gap[dis[u] = md + 1]++;
66             u = pre[u];
67         }
68     }
69     return ans;
70 }
71
72 int main() {
73     while(~scanf("%d", &n)) {
74         memset(head, -1, sizeof(head)); tot = 0;
75         int S = 0, T = n * n + 1; LL sum = 0;
76         for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) scanf("%d", &mp[i][j]), sum += mp[i][j];
77         for(int i = 1; i <= n; i++) {
78             for(int j = 1; j <= n; j++) {
79                 if((i + j) % 2) Add(S, (i - 1) * n + j, mp[i][j]);
80                 else Add((i - 1) * n + j, T, mp[i][j]);
81                 for(int k = 0; k < 4; k++) {
82                     int nx = i + dx[k], ny = j + dy[k];
83                     if(check(nx, ny) && (i + j) % 2) Add((i - 1) * n + j, (nx - 1) * n + ny, INF);
84                 }
85             }
86         }
87         printf("%lld\n", sum - ISAP(S, T, T + 1));
88     }
89     return 0;
90 }

点覆盖集

vertex covering set

VCS

)是无向图

的一个点集,使得该图中所有边都至少

有一个端点在该集合内。形式化的定义是点覆盖集为

G

V

V

(

,

)

u

v

E

,满足对于

,都有

成立,即

u

V

v

V

u

V

v

V

至少一个成立。形象地说是若干个点“覆盖”住了

与它们邻接的边,这些边恰好组成了原边集。

点独立集

vertex independent set

VIS

)是无向图

的一个点集,使得任两个在该集合中

的点在原图中都不相邻。或者说是导出子图为零图(没有边)的点集。形式化的定义是点独

立集为

,满足对于

,都有

G

V

V

,

u

v

V

(

,

)

u

v

E

成立。点独立集还有一种等价的定义:

点独立集为

,满足对于

,都有

V

V

u

V

v

V

(

,

)

u

v

E

不同时成立。

时间: 2024-08-06 06:03:41

HDU 1565:方格取数(1)(最大点权独立集)***的相关文章

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个格子不能相邻,并且取出的数的

HDU 1569 - 方格取数(2) - [最大点权独立集与最小点权覆盖集]

嗯,这是关于最大点权独立集与最小点权覆盖集的姿势,很简单对吧,然后开始看题. HDU1569: Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Problem Description 给你一个m*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大. Input 包括多个测试实例,

HDU 1565 1569 方格取数(最大点权独立集)

HDU 1565 1569 方格取数(最大点权独立集) 题目链接 题意:中文题 思路:最大点权独立集 = 总权值 - 最小割 = 总权值 - 最大流 那么原图周围不能连边,那么就能够分成黑白棋盘.源点连向黑点.白点连向汇点,容量都为点容量.然后黑白之间相邻的就连一条容量无限大的边 代码: #include <cstdio> #include <cstring> #include <queue> #include <algorithm> using names

hdoj 1569 方格取数 【最大点权独立集-&gt;最大流】

题目:hdoj 1569 方格取数 题意:中文题目,就不说题意了. 分类:最大流 |  dp 分析:dp的话应该是个数塔模型,不难做,这里讲转化为图的做法. 这个题目的关键在于转化为一个二分图,来求一个二分图的最大点权独立集,而最大点权独立集 = 点权和 - 最小点权覆盖 最小点权覆盖: 从x或者y集合中选取一些点,使这些点覆盖所有的边,并且选出来的点的权值尽可能小. 最大点权独立集:找到二分图中权值和最大的点集,然后让任意点没有边. 而最小点权覆盖 = 最小割 = 最大流 = sum - 最大

TOJ 3665 方格取数(2)(最大点权独立集)

描述 给你一个m*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大. 输入 包括多个测试实例,每个测试实例包括2整数m,n和m行n列的非负数(m<=50,n<=50) 输出 对于每个测试实例,输出可能取得的最大的和 样例输入 3 375 15 21 75 15 28 34 70 5 样例输出 188 题意 如上 题解 最大点权独立集=总权值-最小点权覆盖 用最小割跑出来的是最小点权覆盖,

hdu 1565 方格取数(2)(网络流之最大点权独立集)

题目链接:hdu 1565 方格取数(2) 题意: 有一个n*m的方格,每个方格有一个数,现在让你选一些数.使得和最大. 选的数不能有相邻的. 题解: 我们知道对于普通二分图来说,最大独立点集 + 最小点覆盖集 = 总点数,类似的,对于有权的二分图来说,有: 最大点权独立集 + 最小点权覆盖集 = 总点权和, 这个题很明显是要求 最大点权独立集 ,现在 总点权 已知,我们只要求出来 最小点权覆盖集 就好了,我们可以这样建图, 1,对矩阵中的点进行黑白着色(相邻的点颜色不同),从源点向黑色的点连一

网络流 [HDU 1565] 方格取数(1)

方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5961    Accepted Submission(s): 2268 Problem Description 给你一个n*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数

hdu 1565 方格取数(1)

这个题网上很多人都说用状态压缩dp来做,我就是觉得状态压缩dp有点那么理解不上啊,不过如果这个题吧相邻的两个格子连起来,那不就是求最大权独立点集吗?奋战了三天,我的第一道最大流题目终于写出来了,高兴啊! #include<map> #include<set> #include<stack> #include<queue> #include<cmath> #include<vector> #include<cstdio> #

HDU 1565 方格取数(1) (状态压缩DP)

HDU 1565 方格取数(1) (状态压缩DP) ACM 题目地址: HDU 1565 方格取数(1) 题意: 中文. 分析: dp[i][j]表示前i行状态j的最优解. 先预处理出符合条件的数,17000+个(n在20以内). 不过感觉复杂度挺高的会T,但是却能A. 这题的正解应该是最小割,回头补下. 代码: /* * Author: illuz <iilluzen[at]gmail.com> * File: 1565_dp.cpp * Create Date: 2014-09-19 23

HDU 1565 方格取数(1) (状态压缩 DP)

方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5779    Accepted Submission(s): 2194 Problem Description 给你一个n*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出