zoukankan      html  css  js  c++  java
  • Luogu1646 happiness

    Description

    link

    Solution

    按照最小割求最大权闭合子图的思路,我们先这样:

    [add(S,id_{wen}) add(id_{li},T) ]

    然后我们求最小割的时候割哪个就代表不选哪个(其实不大一样……)

    对于同桌和前后桌的情况,我们对含义建图:

    新拎出来一个点 (x)

    如果是文科相关就 (add(S,x,val)) 同时,从这个点向相邻的两个点建边,权重 (inf)

    理科就 (add(x,T,val)) 同时从相关联的点向这个点建边,权重 (inf)

    跑一遍最小割即可,拿总的边权和减去最小割

    正确性?

    为啥每个人只能选一科?

    画画图,思考一下连通性就能证完了(或者参考这里的图画画)

    Code

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    namespace yspm{
    	inline int read()
    	{
    		int res=0,f=1; char k;
    		while(!isdigit(k=getchar())) if(k=='-') f=-1;
    		while(isdigit(k)) res=res*10+k-'0',k=getchar(); 
    		return res*f;
    	}
    	const int N=7e5+10;
    	struct node{
    		int to,lim,nxt;
    	}e[N<<1];
    	int head[N],cnt=1,dep[N],sum,S,T,n,m,tot;
    	inline void adde(int u,int v,int w)
    	{
    		e[++cnt].lim=w; e[cnt].to=v; e[cnt].nxt=head[u];
    		return head[u]=cnt,void();
    	} queue<int> q;
    	inline void add(int u,int v,int w){return adde(u,v,w),adde(v,u,0);}
    	inline bool bfs()
    	{
    		memset(dep,0,sizeof(dep)); dep[S]=1;
    		while(q.size()) q.pop(); q.push(S);
    		while(!q.empty())
    		{
    			int fr=q.front(); q.pop();
    			for(int i=head[fr];i;i=e[i].nxt)
    			{
    				int t=e[i].to; 
    				if(!dep[t]&&e[i].lim) dep[t]=dep[fr]+1,q.push(t);
    			}
    		} return dep[T];
    	}
    	inline int dfs(int now,int in)
    	{
    		if(now==T) return in; int out=0;
    		for(int i=head[now];i&&in;i=e[i].nxt)
    		{
    			int t=e[i].to; 
    			if(e[i].lim&&dep[t]==dep[now]+1)
    			{
    				int res=dfs(t,min(e[i].lim,in));
    				in-=res; out+=res; e[i].lim-=res; e[i^1].lim+=res;
    			}
    		}if(!out) dep[now]=0;
    		return out;
    	}
    	inline int id(int x,int y){return (x-1)*m+y;}
    	signed main()
    	{
    		n=read(); m=read(); tot=n*m+2; S=n*m+1,T=n*m+2;
    		for(int i=1;i<=n;++i)
    		{
    			for(int j=1;j<=m;++j)
    			{
    				int x=read(); sum+=x;
    				add(S,id(i,j),x);
    			}
    		}
    		for(int i=1;i<=n;++i)
    		{
    			for(int j=1;j<=m;++j)
    			{
    				int x=read(); sum+=x;
    				add(id(i,j),T,x);
    			}
    		}
    		for(int i=1;i<n;++i)
    		{
    			for(int j=1;j<=m;++j)
    			{
    				int x=read(); ++tot; 
    				add(S,tot,x); sum+=x;
    				add(tot,id(i+1,j),1e18+10);
    				add(tot,id(i,j),1e18+10);
    			}
    		}
    		for(int i=1;i<n;++i)
    		{
    			for(int j=1;j<=m;++j)
    			{
    				int x=read(); ++tot; 
    				add(tot,T,x); sum+=x; 
    				add(id(i,j),tot,1e18+10);
    				add(id(i+1,j),tot,1e18+10); 
    			}
    		}
    		for(int i=1;i<=n;++i)
    		{
    			for(int j=1;j<m;++j)
    			{
    				int x=read(); ++tot; 
    				add(S,tot,x); sum+=x; 
    				add(tot,id(i,j),1e18+10);
    				add(tot,id(i,j+1),1e18+10); 
    			}
    		}for(int i=1;i<=n;++i) 
    		{
    			for(int j=1;j<m;++j)
    			{
    				int x=read(); ++tot; 
    				add(tot,T,x); sum+=x;
    				add(id(i,j),tot,1e18+10); 
    				add(id(i,j+1),tot,1e18+10);
    			}
    		}
    		while(bfs()) sum-=dfs(S,1e18+10); 
    		printf("%lld
    ",sum);
    		return 0;
    	}
    }
    signed main(){return yspm::main();}
    

    Review

    1.网络流中逆向思维比较多,比如这种(max=sum-mincut)

    2.最小割题目从含义下手,然后根据含义进行网络图的建立

    一般在这里都是割啥啥没有的

  • 相关阅读:
    mac 显示隐藏文件 快捷键
    Swift常用内置函数介绍
    MacOS Catalina 虚拟机VMware Fusion 重装教程 和问题
    swift 时间显示格式
    mybatis自测错题总结
    Spring核心概念和案例
    MyBatis注解
    MyBatis缓存
    关联查询
    智能标签
  • 原文地址:https://www.cnblogs.com/yspm/p/13097226.html
Copyright © 2011-2022 走看看