hdu1565 方格取数(1)--最大点权独立集 & Dinic
原创
©著作权归作者所有:来自51CTO博客作者Limer123的原创作品,请联系作者获取转载授权,否则将追究法律责任
原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1565
题意:
先设置一个源点(0)和一个汇点( n*n+1),一开始初始化的时候把源点到所有 (i+j)%2 ==1的格子全部给个值,
然后初始化把汇点到所有 (i+j) %2 == 0的格子也给个值,值就是这个格子数字。还有,二维数组flow[i][j]用来标记边。然后求最大点权独立集即可。
最大点权独立集=总权值-最小点权覆盖集。
最小点权覆盖集=图的最小割值=最大流。
#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int INF = 9999999999;
int chess[25][25];
int flow[25 * 25][25 * 25];
int d[25 * 25];
int n;
int sum;
int s, t;
int dir[4][2] = { 0,1,-1,0,0,-1,1,0 };
bool bfs()
{
memset(d, 0, sizeof(d));
queue<int> Q;
Q.push(s);
d[s] = 1;
while (!Q.empty())
{
int u = Q.front();
Q.pop();
for (int v = 1; v <= n*n + 1; v++)
{
if (flow[u][v] > 0 && d[v] == 0)
{
d[v] = d[u] + 1;
Q.push(v);
}
}
}
return d[t] != 0;
}
int dfs(int u, int w)
{
if (u == t)
return w;
int ans = 0;
for (int v = 0; v <= n*n + 1; v++)
{
if (flow[u][v] > 0 && d[v] == d[u] + 1)
{
int x = dfs(v, min(w - ans, flow[u][v]));//
if (x)
{
ans += x;
flow[u][v] -= x;
flow[v][u] += x;
if (ans == w)
return w;
}
}
}
if (ans == 0)
d[u] = 0;
return ans;
}
int dinic()
{
int ans = 0;
int p;
while (bfs())
while (p = dfs(s, INF))
ans += p;
return ans;
}
int main()
{
while (~scanf("%d", &n))
{
sum = 0;
memset(flow, 0, sizeof(flow));
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
scanf("%d", &chess[i][j]);
sum += chess[i][j];
if ((i + j) % 2 == 0)
flow[0][(i - 1)*n + j] = chess[i][j];
else
flow[(i - 1)*n + j][n*n + 1] = chess[i][j];
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
for (int k = 0; k < 4; k++)
{
int x = i + dir[k][0];
int y = j + dir[k][1];
if (x >= 1 && x <= n&&y >= 1 & y <= n && (i + j) % 2 == 0)//注意只有与s点直接相邻的才可以
flow[(i - 1)*n + j][(x - 1)*n + y] = INF;
}
}
}
s = 0;
t = n*n + 1;
printf("%d\n", sum - dinic());
}
return 0;
}