网络流24题呀,然后就使劲的各种建图搞,但发现还是搞不了。始终不能解决的问题就是,会出现相邻的方块,但是他们都被选了。
还是太弱鸡了,这题是将整个图染成黑白相间的颜色。拿着整个图值的总和 - 我们最终扣掉的那些方格的值。所以就转换成求最小的扣掉的那些方格的值。建立二分图,左边是白方格集合X,右边是黑方格集合Y。然后在相邻的方格之间建边,也就是在X和Y之间建边。这个时候跑出的最大流就是最小割。
这样求解为啥对呢?我们需要选择一些的相邻的点,使得他们的值的和最小,并且去掉他们之后剩下的点都是不相邻的。求出最小割,就是使得剩下点不存在相邻的边,并且剩下点的值尽量的大。
感觉值得学习是这个转换成二分图的思想,另外二分图的最大匹配通俗一点来说就是X点集合和Y点集合之间不会再存在多余的点相互之间有联系,因为已经尽可能的进行匹配了。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define llinf 1e17
const int maxn=105;
int n,m,g[maxn][maxn];
int ans=2,head[maxn*maxn*2],S,T;
int deep[maxn*maxn*2],que[maxn*maxn*2],cur[maxn*maxn*2];
bool isblack[maxn][maxn];
struct edge{
int to,next,v;
}e[100000];
void add(int x,int y,int v){
e[ans].to=y; e[ans].next=head[x]; e[ans].v=v;
head[x]=ans++;
e[ans].to=x; e[ans].next=head[y]; e[ans].v=0;
head[y]=ans++;
}
bool bfs(int S,int T)
{
for(int i=0;i<=n;i++) cur[i]=head[i];//当前弧优化
memset(deep,0,sizeof(deep));
int l=1,r=1;
deep[S]=1;
que[1]=S;
while(l<=r){
int x=que[l];
for(int i=head[x];i;i=e[i].next){
int y=e[i].to,v=e[i].v;
if(!deep[y]&&v){//易忽略边不为0
deep[y]=deep[x]+1;
que[++r]=y;
}
}
l++;
}
if(deep[T]) return true;
else return false;
}
int dfs(int x,int dist){
if(x==T||0==dist) return dist;
int res=0,tp;
for(int i=cur[x];i;i=e[i].next){
cur[x]=i;//当前弧优化
int y=e[i].to;
if(deep[y]==deep[x]+1&&e[i].v){//易忽略边不为0
tp=dfs(y,min(dist,e[i].v));
e[i].v-=tp;
e[i^1].v+=tp;
res+=tp;
dist-=tp;
if(0==dist) break;
}
}
if(!res) deep[x]=0;//这个优化真是。。。加上效果太明显了
return res;
}
bool isin(int x,int y){
if(x>n||y>m||x<1||y<1) return false;
else return true;
}
int main()
{
scanf("%d%d",&n,&m);
int sum=0;
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
scanf("%d",&g[i][j]),sum+=g[i][j];
S=0,T=n*m*2+1;
bool salix=true;
for(int i=1;i<=n;i++){
int flag;
if(salix) flag=true;
else flag=false;
for(int j=1;j<=m;j++){
if(flag) isblack[i][j]=true;
else isblack[i][j]=false;
flag=!flag;
}
salix=!salix;
}
for(int i=1;i<=n*m;i++){
int x=i/m,y=i-i/m*m;
if(i%m) x++;
if(0==y) y=m;
add(i,i+n*m,g[x][y]);
if(isblack[x][y]) add(S,i,inf);
else add(i+n*m,T,inf);
}
for(int i=1;i<=n*m;i++){
int x=i/m,y=i-i/m*m;
if(i%m) x++;
if(0==y) y=m;
if(isin(x,y+1)){
if(isblack[x][y]) add(i+n*m,i+1,inf);
else add(i+1+n*m,i,inf);
}
if(isin(x+1,y)){
if(isblack[x][y]) add(i+n*m,i+m,inf);
else add(i+m+n*m,i,inf);
}
}
n=n*m*2+1;
int ans=0;
while(bfs(S,T)){
ans+=dfs(S,inf);
}
printf("%d",sum-ans);
return 0;
}