Description
小N手上有一個N*M的方格圖,控制某一個點要付出Aij的代價,然後某個點如果被控制了,或者他周圍的所有點(上下左右)都被控制了,那麼他就算是被選擇了的。一個點如果被選擇了,那麼可以得到Bij的回報,現在請你幫小N選一個最優的方案,使得回報-代價儘可能大。
Input
第一行兩個正整數N,M表示方格圖的長與寬。
接下來N行每行M個整數Aij表示控制的代價。
接下來N行每行M個整數Bij表示選擇的回報。
Output
一個整數,表示最大的回報-代價(如果一個都不控制那麼就是0)。
Sample Input
3 3
1 100 100
100 1 100
1 100 100
2 0 0
5 2 0
2 0 0
Sample Output
8
HINT
對於100%的數據,N,M<=50,Aij,Bij都是小於等於100的正整數。
第一眼看見這道題,約束條件既有串又有並,根本沒法建邊啊!!!
後來上網一看,棋盤紅黑染色是什麼鬼。。。
反正後來畫了個圖,大概明白了。
我們先把棋盤上的格子分爲奇數格和偶數格(x+y的奇偶性)
然後這樣建邊(反正講是講不清楚)
紅色的代表佔領該點的代價,綠色代表控制該點的收益,黑色代表邊權爲INT_MAX。
其中第一個圖代表一個點和它周圍幾個點的連邊。
剩下的看代碼:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<stack>
using namespace std;
#define MAXN 50
#define MAXM 50
#define INF 0x3f3f3f3f
typedef long long int LL;
int getint(){
int rn=0;char c=getchar();bool flag=0;
while(c<'0'||'9'<c){if(c=='-')flag=1;c=getchar();}
while('0'<=c&&c<='9'){rn=rn*10+c-'0';c=getchar();}
return flag?-rn:rn;
}
namespace ISAP{
const int MAXP = MAXN*MAXM*3;
const int MAXE = MAXN*MAXM*10;
struct node{
int v,c;
node *nxt,*bck;
}*adj[MAXP+10],Edges[MAXE*2+100],*New;
int S,T,P;
int d[MAXP+10],vd[MAXP+10];
void init(int s,int t,int p){
S=s,T=t,P=p;
New=Edges;
memset(adj,0,sizeof(adj));
}
void addedges(int u,int v,int c){
node *p=++New;
p->v=v;
p->c=c;
p->nxt=adj[u];
p->bck=New+1;
adj[u]=p;
p=++New;
p->v=u;
p->c=0;
p->nxt=adj[v];
p->bck=New-1;
adj[v]=p;
}
int aug(int x,int augco){
if(x==T)return augco;
int Dmin=P-1,delta,augc=augco;
for(node *p=adj[x];p!=NULL;p=p->nxt)
if(p->c){
if(d[x]==d[p->v]+1){
delta=min(augc,p->c);
delta=aug(p->v,delta);
augc-=delta;
p->c-=delta;
p->bck->c+=delta;
if(d[S]>=P)
return augco-augc;
if(!augc)
break;
}
Dmin=min(Dmin,d[p->v]);
}
if(augco==augc){
if(!(--vd[d[x]]))
d[S]=P;
++vd[d[x]=Dmin+1];
}
return augco-augc;
}
int isap(){
memset(d,0,sizeof(d));
memset(vd,0,sizeof(vd));
vd[0]=P;
int flow=0;
while(d[S]<P)
flow+=aug(S,INF);
return flow;
}
}
const int dx[4]={0,1,0,-1};
const int dy[4]={1,0,-1,0};
int M,N,Cnt;
int id[MAXM+10][MAXN+10][2];
void Mark(){
Cnt=0;
for(int i=1;i<=M;++i)
for(int j=1;j<=N;++j)
id[i][j][0]=++Cnt,id[i][j][1]=++Cnt;
}
int main(){
M=getint(),N=getint();
int ans=0;
Mark();
ISAP::init(Cnt+1,Cnt+2,Cnt+2);
int val;
for(int i=1;i<=M;++i)//佔領代價
for(int j=1;j<=N;++j){
val=getint();
if((i+j)&1)
ISAP::addedges(ISAP::S,id[i][j][0],val);
else
ISAP::addedges(id[i][j][0],ISAP::T,val);
}
for(int i=1;i<=M;++i)//控制收益
for(int j=1;j<=N;++j){
val=getint();
ans+=val+val;
if((i+j)&1){
ISAP::addedges(ISAP::S,id[i][j][1],val);
ISAP::addedges(id[i][j][0],ISAP::T,val);
}
else{
ISAP::addedges(ISAP::S,id[i][j][0],val);
ISAP::addedges(id[i][j][1],ISAP::T,val);
}
}
int nx,ny;
for(int i=1;i<=M;++i)
for(int j=1;j<=N;++j){
if((i+j)&1){
ISAP::addedges(id[i][j][1],id[i][j][0],INF);
for(int k=0;k<4;++k){
nx=i+dx[k],ny=j+dy[k];
if(nx<1||ny<1||nx>M||ny>N)continue;
ISAP::addedges(id[i][j][1],id[nx][ny][0],INF);
}
}
else{
ISAP::addedges(id[i][j][0],id[i][j][1],INF);
for(int k=0;k<4;++k){
nx=i+dx[k],ny=j+dy[k];
if(nx<1||ny<1||nx>M||ny>N)continue;
ISAP::addedges(id[nx][ny][0],id[i][j][1],INF);
}
}
}
printf("%d\n",ans-ISAP::isap());
}