题目链接:
题目大意:
给出一个方格,每个格存在一个具有权值的点,去除不相邻的一些数,使得出的权值和最大
题目分析:
我们把相邻当做一种关系建边,然后横纵坐标相加之和是奇数的点和横纵之和相加是偶数的点一定不会存在边,所以这个图就变成了一个二分图,那么问题也就抽象为了求最大权独立点集,最大权独立点集因为和最小权覆盖集互为补集,所以我们可以先求出最小权覆盖集,首先我们考虑建图的方法:
1.根据划分出的二分图,左集中的点与源点相连,边权就等于点权,右集的点与汇点相连,边权就等于点权,原图中的边将左集中的点连向右集,边权定为INF,那么接下来我们考虑为何要这么建图
2.根据最小割的定义,我们求取最大流也就是最小割,是将当前图分为S集合T集,切掉的边流量之和最小的,也就是去掉点权之和最少的点,导致所有相连的点都不能从原点到达汇点,也就是切掉其中一条点权边,那么就相当于将这个点放入了最小权点覆盖集,那么最大权点独立集,直接利用总点权减去最小割即可
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#define MAX 507
#define INF (1<<29)
using namespace std;
struct Edge
{
int u,v,flow,next;
}e[MAX*MAX];
int head[MAX];
int cc;
void init ( )
{
memset ( head, -1 , sizeof ( head ));
cc = 0;
}
void add ( int u , int v , int c )
{
e[cc].u = u;
e[cc].v = v;
e[cc].flow = c;
e[cc].next = head[u];
head[u] = cc++;
e[cc].u = v;
e[cc].v = u;
e[cc].flow = 0;
e[cc].next = head[v];
head[v] = cc++;
}
int S,T,n;
int d[MAX];
bool bfs ( )
{
int q[MAX],iq=0;
memset ( d , 0 , sizeof ( d ));
d[S] = 1;
q[iq++] = S;
for ( int i = 0 ; i < iq ; i++ )
{
int u = q[i];
if ( u == T ) return true;
for ( int j = head[u]; j != -1 ; j = e[j].next )
{
int v = e[j].v;
if ( !d[v] && e[j].flow )
{
q[iq++] = v;
d[v] = d[u]+1;
}
}
}
return false;
}
int dfs ( int u , int cur_flow )
{
if ( u == T ) return cur_flow;
int ret = 0;
for ( int i = head[u] ; i != -1 ; i = e[i].next )
{
int v = e[i].v;
if ( e[i].flow&& d[u]+1 == d[v] )
{
int flow = dfs ( v , min ( cur_flow - ret, e[i].flow ));
e[i].flow -= flow;
e[i^1].flow += flow;
ret += flow;
if ( ret == cur_flow ) return ret;
}
}
return ret;
}
int dinic ( )
{
int cur_flow, ans = 0;
while ( bfs ())
{
while ( cur_flow = dfs ( S , INF))
ans += cur_flow;
}
return ans;
}
int mp[27][27];
int id[27][27];
int dx[]={0,1,0,-1};
int dy[]={1,0,-1,0};
bool check ( int x ,int y )
{
if ( x < 0 || x >= n || y < 0 || y >= n )
return true;
return false;
}
int main ( )
{
while ( ~scanf ( "%d" , &n ))
{
int sum = 0;
for ( int i = 0 ; i < n ; i++ )
for ( int j = 0 ; j < n ; j++ )
{
scanf ( "%d" , &mp[i][j] );
sum += mp[i][j];
}
int cnt = 1;
for ( int i = 0 ; i < n ; i++ )
for ( int j = 0 ; j < n ; j++ )
id[i][j] = cnt++;
S = 0 , T = cnt;
init();
for ( int i = 0 ; i < n ; i++ )
for ( int j = 0 ; j < n ; j++ )
{
if ( (i+j)%2 == 1 )
{
add ( S , id[i][j] , mp[i][j] );
for ( int k = 0 ; k < 4 ; k++ )
{
int x = i + dx[k];
int y = j + dy[k];
if (check ( x , y )) continue;
add ( id[i][j] , id[x][y] , INF );
}
}
else
add ( id[i][j] , T , mp[i][j] );
}
printf ( "%d\n" , sum - dinic());
}
}