zoukankan      html  css  js  c++  java
  • 洛谷P1935 [国家集训队]圈地计划

    题目大意:

    有个(n*m)的网格图

    每个点可以选择(A),获得(A[i][j])或选(B)获得(B[i][j])的收益

    相邻点有(k)个不同可以获得(C[i][j])的收益,求最大收益

    类似与文理分科那题,不过这次是相邻不同有额外收益,需要稍微变形一下

    我们把网格黑白染色

    对于黑色点向(S)(A[i][j])边,向汇点连(B[i][j])

    对于白色点向(S)(B[i][j])边,向汇点连(A[i][j])

    然后对于相邻点互相连(C[x][y]+C[tx][ty])

    这样满足相邻格子选择相同类型时需要鸽掉中间边

    #include<bits/stdc++.h>
    using namespace std;
    inline int read()
    {
    	int x=0,f=1;
    	char ch;
    	for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    	if(ch=='-') f=0,ch=getchar();
    	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    	return f?x:-x;
    }
    const int inf=0x3f3f3f3f;
    int dx[5]={0,-1,0,1,0},dy[5]={0,0,1,0,-1};
    int n,m,sum,tot,st,ed,ret;
    int val[110][110][3];
    int id[110][110];
    bool col[110][110];
    int head[100010],cur[100010],d[10000],cnt=1;
    struct point
    {
    	int nxt,to,c;
    }a[200010];
    inline void add(int x,int y,int c)
    {
    	a[++cnt]=(point){head[x],y,c};head[x]=cnt;
    	a[++cnt]=(point){head[y],x,0};head[y]=cnt;//大草
    }
    queue<int> q;
    inline bool bfs()
    {
    	for(int i=1;i<=tot;++i)
    	{
    		cur[i]=head[i];
    		d[i]=0;
    	}
    	q.push(st);d[st]=1;
    	while(!q.empty())
    	{
    		int now=q.front();
    		q.pop();
    		for(int i=head[now];i;i=a[i].nxt)
    		{
    			int t=a[i].to;
    			if(!d[t]&&a[i].c)
    			{
    				d[t]=d[now]+1;
    				q.push(t);
    			}
    		}
    	}
    	return d[ed];
    }
    inline int dfs(int now,int c)
    {
    	if(now==ed||!c) return c;
    	int ret=c,f;
    	for(int i=cur[now];i;i=a[i].nxt)
    	{
    		cur[now]=i;
    		int t=a[i].to;
    		if(d[t]==d[now]+1)
    		{
    			f=dfs(t,min(a[i].c,ret));
    			if(!f) continue;
    			a[i].c-=f;
    			a[i^1].c+=f;
    			ret-=f;
    			if(!ret) return c;
    		}
    	}
    	if(ret==c) d[now]=0;
    	return c-ret;
    }
    inline int dinic()
    {
    	int ret=0;
    	while(bfs()) ret+=dfs(st,inf);
    	return ret;
    }
    signed main()//黑白染色,黑点源点连a[i][j]边,汇点连b[i][j]边,四周连c[i][j]+c[tx][ty]边
    {
    	n=read(),m=read();
    	for(int k=0;k<=2;++k)
    	{
    		for(int i=1;i<=n;++i)
    		{
    			for(int j=1;j<=m;++j)
    			{
    				val[i][j][k]=read();
    				if(!k) id[i][j]=++tot,col[i][j]=((i+j)&1);
    			}
    		}
    	}
    	st=++tot,ed=++tot;
    	for(int i=1;i<=n;++i)
    	{
    		for(int j=1;j<=m;++j)
    		{
    			sum+=val[i][j][0]+val[i][j][1];
    			add(st,id[i][j],val[i][j][col[i][j]^1]);
    			add(id[i][j],ed,val[i][j][col[i][j]]);
    			for(int k=1;k<=4;++k)
    			{
    				int tx=i+dx[k],ty=j+dy[k];
    				if(tx<1||ty<1||tx>n||ty>m) continue;
    				add(id[i][j],id[tx][ty],val[i][j][2]+val[tx][ty][2]);//选相同的种类会割掉中间边,很稳
    				sum+=val[i][j][2];
    			}
    		}
    	}
    	printf("%d
    ",sum-dinic());
    return 0;
    }
    
  • 相关阅读:
    JavaScript 中,定义函数时用 var foo = function () {} 和 function foo() 有什么区别?
    Vue报错 [Vue warn]: Cannot find element
    一个android样本的过保护
    cve-2015-1635漏洞分析
    一个linux的样本分析
    ios透明代理抓包
    各浏览器抗uaf机制
    面试知识点总结之Nginx
    面试知识点总结之redis
    面试知识点总结之I/O流IO/BIO/NIO/AIO区别
  • 原文地址:https://www.cnblogs.com/knife-rose/p/12095356.html
Copyright © 2011-2022 走看看