H y p e r l i n k Hyperlink Hyperlink
https://www.luogu.com.cn/problem/P4313
D e s c r i p t i o n Description Description
给定一个 n × m n\times m n×m格子,将 ( i , j ) (i,j) (i,j)染成黑有 a r t [ i ] [ j ] art[i][j] art[i][j]的价值,将 ( i , j ) (i,j) (i,j)染成白有 s c i [ i ] [ j ] sci[i][j] sci[i][j]的价值,如果一个格子和它周围的格子都是黑,则有 s a r [ i ] [ j ] sar[i][j] sar[i][j]的价值,如果一个格子和它周围的格子都是白,则有 s s c [ i ] [ j ] ssc[i][j] ssc[i][j]的价值
求确定一种染色方案,使得价值最大
数据范围: n , m ≤ 100 n,m\leq 100 n,m≤100
S o l u t i o n Solution Solution
看到这个不能爆搜却又比较小的数据范围就想到了最小割
显然一个格子不是染黑就是染白,我们将它们分在两边,分别与源点和汇点相连,即 s − > a s->a s−>a, b − > t , s − > a 1 , b 2 − > t b->t,s->a_1,b_2->t b−>t,s−>a1,b2−>t容量分别为 a r t , s c i , s a r , s s c art,sci,sar,ssc art,sci,sar,ssc【表示对黑白的取舍】
考虑计算 s c i sci sci和 s s c ssc ssc的价值,对于每个点进行拆点,拆成 x x x, x 1 x_1 x1, x 2 x_2 x2,对于与 x x x相连的点 y y y( y y y可以是 x x x)
则 x − > y 2 , y 1 − > x x->y_2,y_1->x x−>y2,y1−>x,容量为 1 e 9 1e9 1e9【表示这种关系不可割舍】
用可获得的价值减去最小割即可
C o d e Code Code
#pragma GCC optimize(2)
%:pragma GCC optimize(3)
%:pragma GCC optimize("Ofast")
%:pragma GCC optimize("inline")
#include<cstring>
#include<cstdio>
#include<queue>
#define min(a,b) a<b?a:b
#define N 30510
#define M 300010
#define id(i,j) (i-1)*m+j
using namespace std;int n,m,x,y;char c;
char str[21];
const short dx[5]={-1,0,1,0,0};
const short dy[5]={0,1,0,-1,0};
int read()
{
int f=0,p=1;
while(c=getchar(),c<=47||c>=58) if(c=='-') p=-1;f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),c>=48&&c<=57) f=(f<<3)+(f<<1)+c-48;
return p*f;
}
struct node{int next,to,w;}e[M];int l[N],tot,d[N],s,t,sum,art[101][101],sci[101][101],sar[101][101],ssc[101][101];
void add(int u,int v,int w)
{
e[tot].next=l[u];e[tot].to=v;e[tot].w=w;l[u]=tot++;
e[tot].next=l[v];e[tot].to=u;e[tot].w=0;l[v]=tot++;
return;
}
bool bfs()
{
memset(d,-1,sizeof(d));
queue<int>q;d[s]=0;q.push(s);
while(q.size())
{
int x=q.front();q.pop();
for(int i=l[x];i!=-1;i=e[i].next)
{
int y=e[i].to;
if(e[i].w&&d[y]==-1)
{
d[y]=d[x]+1;
q.push(y);
if(y==t) return true;
}
}
}
return false;
}
int dfs(int x,int flow)
{
if(x==t||!flow) return flow;
int rest=0,k=0;
for(int i=l[x];i!=-1;i=e[i].next)
{
int y=e[i].to;
if(d[x]+1==d[y]&&e[i].w)
{
int f=dfs(y,min(flow-rest,e[i].w));
e[i].w-=f;rest+=f;e[i^1].w+=f;
if(rest==flow) return flow;
}
}
if(!rest) d[x]=0;
return rest;
}
int dinic()
{
int r=0;
while(bfs()) r+=dfs(s,1e9);
return r;
}
signed main()
{
memset(l,-1,sizeof(l));
n=read();m=read();
s=0;t=n*m*3+1;
for(register int i=1;i<=n;i++) for(register int j=1;j<=m;j++) art[i][j]=read(),sum+=art[i][j],add(s,id(i,j),art[i][j]);
for(register int i=1;i<=n;i++) for(register int j=1;j<=m;j++) sci[i][j]=read(),sum+=sci[i][j],add(id(i,j),t,sci[i][j]);
for(register int i=1;i<=n;i++) for(register int j=1;j<=m;j++) sar[i][j]=read(),sum+=sar[i][j],add(s,id(i,j)+n*m,sar[i][j]);
for(register int i=1;i<=n;i++) for(register int j=1;j<=m;j++) ssc[i][j]=read(),sum+=ssc[i][j],add(id(i,j)+n*m*2,t,ssc[i][j]);
for(register int i=1;i<=n;i++)
for(register int j=1;j<=m;j++)
for(register int k=0;k<5;k++)
{
int nx=i+dx[k],ny=j+dy[k];
if(nx<1||ny<1||nx>n||ny>m) continue;
add(id(nx,ny)+n*m,id(i,j),1e9);
add(id(i,j),id(nx,ny)+n*m*2,1e9);
}
printf("%d",sum-dinic());
}