您的位置:首页 > 理论基础 > 计算机网络

网络流24题(09)方格取数问题(最大点权独立集 + 最小割最大流)

2013-04-20 21:37 459 查看
题意:

在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数。现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大。

思路:

1. 不清楚何为“最小点权覆盖集”和“最大点权独立集”概念的请看这篇文章《最小割模型在信息学竞赛中的应用》;

2. “最小点权覆盖集”和“最大点权独立集”是两个互补的概念,我们可以利用最小割求一个二分图的最小点权覆盖集;

3. 把黑白相间染色,黑色部分为 X 集,白色部分为 Y 集,s 向 X 中的点引弧, Y 向 t 引弧,容量为 点权的大小;

X 和 Y 中相邻的点由 X 向 Y 引弧,容量为无穷大,这么做的目的是为了让割边仅在 <s, X> 或 <Y, t> 中;

4. 之所以这么做,是因为我们要求这个图中的“最大点权独立集”,依照其概念可以知道:任意两点不相邻<=>任意两点构成的边不在图中;

5. 求上面网络的最大流,并且根据最小割最大流定理,再根据我们的建图,最大流->最小割->最小点权覆盖。输出 = 总点权 - 最大流;

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;

const int MAXN = 50*50;
const int INFS = 0x7FFFFFFF;

struct edge {
int from, to, cap, flow;
edge(int _from, int _to, int _cap, int _flow)
: from(_from), to(_to), cap(_cap), flow(_flow) {}
};

class Dinic {
public:
void initdata(int n, int s, int t) {
this->n = n, this->s = s, this->t = t;
edges.clear();
for (int i = 0; i < n; i++)
G[i].clear();
}
void addedge(int u, int v, int cap) {
edges.push_back(edge(u, v, cap, 0));
edges.push_back(edge(v, u, 0, 0));
G[u].push_back(edges.size() - 2);
G[v].push_back(edges.size() - 1);
}
bool BFS() {
for (int i = 0; i < n; i++)
vis[i] = false, d[i] = 0;
queue<int> Q;
Q.push(s);
vis[s] = true;
while (!Q.empty()) {
int x = Q.front(); Q.pop();
for (int i = 0; i < G[x].size(); i++) {
edge& e = edges[G[x][i]];
if (e.cap > e.flow && !vis[e.to]) {
vis[e.to] = true;
d[e.to] = d[x] + 1;
Q.push(e.to);
}
}
}
return vis[t];
}
int DFS(int x, int aug) {
if (x == t || aug == 0) return aug;
int flow = 0;
for (int i = 0; i < G[x].size(); i++) {
edge& e = edges[G[x][i]];
if (d[e.to] == d[x] + 1) {
int f = DFS(e.to, min(aug, e.cap - e.flow));
if (f <= 0) continue;
e.flow += f;
edges[G[x][i]^1].flow -= f;
flow += f;
aug -= f;
if (aug == 0) break;
}
}
return flow;
}
int maxflow() {
int flow = 0;
while (BFS()) {
flow += DFS(s, INFS);
}
return flow;
}
private:
vector<edge> edges;
vector<int> G[MAXN];
int n, s, t, d[MAXN];
bool vis[MAXN];
};

Dinic dc;
int row, col;
int dir[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};

bool check(int x, int y) {
if (1 <= x && x <= row && 1 <= y && y <= col) {
return true;
}
return false;
}

int main() {
scanf("%d%d", &row, &col);
int sum = 0;
int s = 0, t = row*col + 1;
dc.initdata(t + 1, s, t);
for (int i = 1; i <= row; i++) {
for (int j = 1; j <= col; j++) {
int a;
scanf("%d", &a);
sum += a;
if ((i+j) & 1)
dc.addedge((i-1)*col+j, t, a);
else {
dc.addedge(s, (i-1)*col+j, a);
for (int k = 0; k < 4; k++) {
int x = i + dir[k][0];
int y = j + dir[k][1];
if (check(x, y))
dc.addedge((i-1)*col+j, (x-1)*col+y, INFS);
}
}
}
}
printf("%d\n", sum - dc.maxflow());
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐