正题
题目链接:https://jzoj.net/senior/#contest/show/3014/2
题目大意
n∗mn*mn∗m的地方,每个地方有购买价格和收益,一个地方如果四周都被购买那么也可以获得这个地方的收益。
求收益-价格最大。
解题思路
考虑网络流,进行奇偶染色,对于每个格子我们拆分成xxx和x′x'x′。
有建边
- x−>x′:valxx->x':val_xx−>x′:valx,若割掉这条边,则不要这个点的收益
- 对于奇点s−>x:costxs->x:cost_xs−>x:costx,若割掉这条边,则买下这个点
- 对于偶点x′−>t:costxx'->t:cost_xx′−>t:costx,原理同上
- 对于奇点xxx,和相邻的(偶)点yyy,x−>y:inf,x′−>y′:infx->y:inf,x'->y':infx−>y:inf,x′−>y′:inf这两个点之间的联系,且该联系不可破坏。
然后跑最小割即可。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define p(x,y,z) (((x-1)*m+y)+z*n*m)
using namespace std;
const int N=23*23*2,inf=1e9+7;
const int dx[4]={1,0,-1,0};
const int dy[4]={0,1,0,-1};
struct node{int to,next,w;
}a[N*8];
int c[21][21];
int tot=1,ls[N],dep[N];
int n,m,ans,s,t;
char z[21];
queue<int> q;
int count(char x){if(x>='0'&&x<='9')return x-'0';if(x>='a'&&x<='z')return 10+x-'a';if(x>='A'&&x<='Z')return 36+x-'A';
}
void addl(int x,int y,int w){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w;a[++tot].to=x;a[tot].next=ls[y];ls[y]=tot;a[tot].w=0;
}
bool bfs(){memset(dep,0,sizeof(dep));while(!q.empty()) q.pop();q.push(s);dep[s]=1;while(!q.empty()){int x=q.front();q.pop();for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(dep[y]||!a[i].w) continue;dep[y]=dep[x]+1;if(y==t) return 1;q.push(y);}}return 0;
}
int dinic(int x,int flow){int rest=0,k;if(x==t) return flow;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(dep[x]+1==dep[y]&&a[i].w){rest+=(k=dinic(y,min(a[i].w,flow-rest)));a[i].w-=k;a[i^1].w+=k;if(rest==flow) return flow;}}if(!rest) dep[x]=0;return rest;
}
void net_flow(){while(bfs())ans-=dinic(s,inf);
}
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%s",z+1);for(int j=1;j<=m;j++)c[i][j]=count(z[j]); }s=p(n,m,1)+1;t=s+1;for(int i=1;i<=n;i++){scanf("%s",z+1);for(int j=1;j<=m;j++){int val=count(z[j]);ans+=val;addl(p(i,j,0),p(i,j,1),val);if((i+j)&1){addl(s,p(i,j,0),c[i][j]);for(int k=0;k<4;k++){int x=i+dx[k],y=j+dy[k];if(x<1||y<1||x>n||y>m) continue;addl(p(i,j,1),p(x,y,1),inf);addl(p(i,j,0),p(x,y,0),inf);}}elseaddl(p(i,j,1),t,c[i][j]);}}net_flow();printf("%d",max(ans,0));
}