P2774
思路:
将m*n方格转化成黑白相间的方格,取白色的格子则不能取四周的黑色格子,但是能够取别处的黑色格子。
根据 最大和=全局和-舍弃和 ,我们对相邻的黑白建边,由舍弃和=最小割=最大流,我们跑一边Dinic求出s->黑->白->t 的最小割,减去就是答案。
Code:
#include <bits/stdc++.h>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
const int AX = 6e4 + 666;
int tot ;
int head[AX] ;
int cur[AX] ;
int d[AX] ;
int dir[4][2] = {
{ 1 , 0 },
{ 0 , 1 },
{ -1, 0 },
{ 0 , -1}
};
int s , t ;
struct Node{
int u , v , flow , next1 ;
Node( int u = 0 , int v = 0 , int flow = 0 , int next1 = 0 ):u(u),v(v),flow(flow),next1(next1){}
}G[AX*10];
void addEdge( int u , int v , int w ) {
G[tot] = Node( u , v , w , head[u] ) ; head[u] = tot++;
G[tot] = Node( v , u , 0 , head[v] ) ; head[v] = tot++;
}
bool bfs(){
memset( d , -1 , sizeof(d) ) ;
d[s] = 0 ;
queue<int>q;
q.push(s) ;
while( !q.empty() ){
int u = q.front() ; q.pop() ;
for( int i = head[u] ; ~i ; i = G[i].next1 ){
int v = G[i].v ;
if( d[v] == -1 && G[i].flow ){
d[v] = d[u] + 1 ;
q.push(v) ;
if( v == t ) return true ;
}
}
}return ~d[t] ;
}
int dfs( int u , int cap ){
if( !cap || u == t ) return cap ;
int r = 0 ;
for( int i = cur[u] ; ~i ; i = G[i].next1 ){
int v = G[i].v ;
if( d[v] == d[u] + 1 && G[i].flow ){
int tmp = min( G[i].flow , cap - r ) ;
cur[u] = i ;
tmp = dfs( v , tmp ) ;
r += tmp ;
G[i].flow -= tmp ;
G[i^1].flow += tmp ;
if( r == cap ) break;
}
}if(!r) d[u] -= 2 ;
return r ;
}
int Dinic(){
int cnt = 0 ;
int tmp ;
while( bfs() ){
memcpy( cur , head , sizeof(head) ) ;
while( tmp = dfs( s , INF ) ) cnt += tmp ;
}
return cnt ;
}
int main(){
int m , n ;
scanf("%d%d",&m,&n) ;
LL sum = 0LL ;
tot = 0 ;
memset( head , -1 , sizeof(head) ) ;
s = m * n + 2 ;
t = s + 1 ;
int x ;
for( int i = 0 ; i < m ; i++ ){
for( int j = 0 ; j < n ; j++ ){
scanf("%d",&x) ;
sum += x ;
if( !( ( i + j ) % 2 ) ) addEdge( s , i * n + j , x );
else addEdge( i * n + j , t , x ) ;
}
}
int w, b ;
for( int i = 0 ; i < m ; i++ ){
for( int j = 0 ; j < n ; j++ ){
if( !( ( i + j ) % 2 ) ){ // black
b = i * n + j ;
for( int k = 0 ; k < 4 ; k++ ){
int xx = i + dir[k][0] ;
int yy = j + dir[k][1] ;
if( xx < 0 || xx >= m || yy < 0 || yy >= n ) continue ;
w = xx * n + yy ;
addEdge( b , w , INF ) ;
}
}
}
}
printf("%lld\n",0LL+sum-Dinic());
return 0 ;
}