题目描述
传送门
题目大意:在一个n*n的方格里,每个格子里都有一个正整数。从中取出若干数,使得任意两个取出的数所在格子没有公共边,且取出的数的总和尽量大。
题解
黑白染色。
S-> 所有黑点 容量为格子中的点权
所有白点->T 容量为格子中的点权
相邻的黑白点中间连inf
代码
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#define N 1000003
#define M 33
#define inf 1000000000
using namespace std;
int dx[10]={0,1,0,-1},dy[10]={1,0,-1,0},n,a[M][M],cnt[M][M],mp[M][M];
int point[N],tot,nxt[N],v[N],deep[N],cur[N],num[N],last[N],S,T,remain[N],sz;
void add(int x,int y,int z)
{
tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=z;
tot++; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0;
// cout<<x<<" "<<y<<" "<<z<<endl;
}
int addflow(int s,int t)
{
int now=t; int ans=inf;
while (now!=s) {
ans=min(ans,remain[last[now]]);
now=v[last[now]^1];
}
now=t;
while (now!=s) {
remain[last[now]]-=ans;
remain[last[now]^1]+=ans;
now=v[last[now]^1];
}
return ans;
}
void bfs(int s,int t)
{
for (int i=1;i<=t;i++) deep[i]=t;
deep[t]=0;
queue<int> p; p.push(t);
while (!p.empty()) {
int now=p.front(); p.pop();
for (int i=point[now];i!=-1;i=nxt[i])
if (deep[v[i]]==t&&remain[i^1]) {
deep[v[i]]=deep[now]+1;
p.push(v[i]);
}
}
}
int isap(int s,int t)
{
bfs(s,t); int now=s; int ans=0;
for (int i=1;i<=t;i++) num[deep[i]]++;
for (int i=1;i<=t;i++) cur[i]=point[i];
while (deep[s]<t) {
if (now==t) {
ans+=addflow(s,t);
now=s;
}
bool pd=false;
for (int i=point[now];i!=-1;i=nxt[i])
if (deep[now]==deep[v[i]]+1&&remain[i]) {
cur[now]=i; last[v[i]]=i;
pd=true; now=v[i];
break;
}
if (!pd) {
int minn=t+1;
for (int i=point[now];i!=-1;i=nxt[i])
if (remain[i]) minn=min(minn,deep[v[i]]);
if (!-num[deep[now]]) break;
num[deep[now]=minn+1]++;
cur[now]=point[now];
if (now!=s) now=v[last[now]^1];
}
}
return ans;
}
int main()
{
freopen("a.in","r",stdin);
scanf("%d",&n); tot=-1; int sum=0;
memset(point,-1,sizeof(point));
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++) scanf("%d",&a[i][j]),sum+=a[i][j];
S=1; T=n*n+2; sz=1;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++){
cnt[i][j]=++sz;
if (i&1) mp[i][j]=(j&1?1:0);
else mp[i][j]=((!(j&1))?1:0);
}
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (mp[i][j]) {
add(S,cnt[i][j],a[i][j]);
for (int k=0;k<4;k++) {
int x=i+dx[k]; int y=j+dy[k];
if (x<=0||y<=0||x>n||y>n) continue;
add(cnt[i][j],cnt[x][y],inf);
}
}
else add(cnt[i][j],T,a[i][j]);
printf("%d\n",sum-isap(S,T));
}