题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=1569
题解:
因为这个数据比较大,所以用动态规划会超时。
将图转换成黑白棋盘问题,i + j 为奇数的与s节点相连,边的权值为棋盘上对应位置的值,其他的与t节点相连,
边的权值为棋盘上对应位置的值,然后让棋盘上相邻之间的节点用边相连,边的权值为INF。这样问题就转换为
了最大点权独立集问题。
定理:
1、最大点权独立集 = sum - 最小点权覆盖集。
2、最小点权覆盖集 = 最小割 = 最大流
dinic实现:
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 2550;
const int inf = 0x7fffffff;
struct node
{
int v,cost;
int next;
}edge[8*maxn];
int map[55][55];
int head[maxn],dis[maxn],id;
int source,sink,res;
int n,m;
void add_edge(int u,int v,int cost)
{
edge[id].v = v;edge[id].cost = cost;edge[id].next = head[u];head[u] = id++;
edge[id].v = u;edge[id].cost = 0; edge[id].next = head[v];head[v] = id++;
}
void build()
{
id = source = 0;sink = n*m+5;
memset(head,-1,sizeof(head));
int i,j,t;
for( i = 1; i <= n; i++)
{
for( j = 1; j <= m; j++)
{
t = (i-1)*m+j+1;
if((i+j)&1)
{
add_edge(source,t,map[i][j]);
if( i > 1)
add_edge(t,t-m,inf);
if( i < n )
add_edge(t,t+m,inf);
if( j > 1)
add_edge(t,t-1,inf);
if( j < m )
add_edge(t,t+1,inf);
}
else
add_edge(t,sink,map[i][j]);
}
}
}
bool bfs()
{
memset(dis,-1,sizeof(dis));
queue<int>que;
dis[source] = 0;
que.push(source);
while( !que.empty())
{
int u = que.front();
que.pop();
for( id = head[u] ; id != -1; id = edge[id].next)
{
int v = edge[id].v;
if( edge[id].cost > 0 && dis[v] == -1)
{
dis[v] = dis[u] + 1;
que.push(v);
}
}
}
return dis[sink] != -1;
}
int dinic(int u,int flow)
{
if( u == sink)return flow;
int tmp = flow;
for(int id = head[u] ; id != -1 ; id = edge[id].next)
{
int v = edge[id].v;
if( edge[id].cost > 0 && dis[v] == dis[u] + 1)
{
int c = dinic(v,edge[id].cost < tmp ? edge[id].cost : tmp);
tmp -= c;
edge[id].cost -= c;
edge[id^1].cost += c;
if( tmp == 0)break;
}
}
return flow - tmp;
}
int get_max_flow()
{
int max_flow = 0;
while( bfs() )
max_flow += dinic(source,res);
return max_flow;
}
int main()
{
int i,j;
while( scanf("%d%d",&n,&m) != EOF)
{
res = 0;
for( i = 1; i <= n; i++)
for( j = 1; j <= m; j++)
{
scanf("%d",&map[i][j]);
res += map[i][j];
}
build();
printf("%d\n",res-get_max_flow());
}
return 0;
}