P4313 文理分科

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,m100


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());
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值