• bzoj3894: 文理分科


    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3894

    思路:令S为学文,T为学理

    对于额外的收入,新加一个点

    也可以用二元组建图来解决

    还是这个图,x表示一个学生,与S连通表示学文,与T连通表示学理

    y表示新加的点,用来计算同时学理的额外收益,与S连通表示不要额外收益,与T连通表示要额外收益

    先算出总收益,在用最小割减去即可


    解方程:

    c+d=B[i]+WB//学生i学文,不要额外收益,损失学理收益,损失额外收益
    a+b=A[i]//学生i学理,要额外收益,损失学文收益
    b+e+c=inf//学生i学文,要额外收益,这不可能,损失为inf
    a+f+d=A[i]+WB//学生i学理,不要额外收益,损失学文收益,损失额外收益

    a=A[i]
    b=0
    c=B[i]
    d=WB
    e=inf
    f=0

    学文类似,但要注意一些边方向不同,收益也不同


    所以最终建图就是:

    S向每个学生连边,容量为学文的收益,每个学生向T连边,容量为学理的收益

    S向每个代表相邻5个人都学文收益点连边,容量为同时学文的收益

    该点再向对应5个人连边,容量为inf,表示只要有人学理,就必须割掉同时学文的收益

    学理类似

    对应5个人向该点连inf的边,该点向T连同时学理的收益的边


    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    const int maxn=30010,maxm=1000010,inf=1061109567;
    const int dx[]={0,0,0,1,-1};
    const int dy[]={0,1,-1,0,0};
    using namespace std;
    int n,m,sum;
    int stu(int x,int y){return (x-1)*m+y;}
    int art(int x,int y){return (x-1)*m+y+n*m;}
    int sci(int x,int y){return (x-1)*m+y+n*m*2;}
    
    struct Flow{
    	int pre[maxm],now[maxn],son[maxm],val[maxm],tot,dis[maxn],q[maxn+10],head,tail,S,T;
    	void add(int a,int b,int c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;}
    	void ins(int a,int b,int c){add(a,b,c),add(b,a,0);}
    	void init(){memset(now,0,sizeof(now)),tot=1,S=0,T=3*n*m+1;}
    	void build(){
    		for (int i=1,x;i<=n;i++) for (int j=1;j<=m;j++) scanf("%d",&x),sum+=x,ins(S,stu(i,j),x);
    		for (int i=1,x;i<=n;i++) for (int j=1;j<=m;j++) scanf("%d",&x),sum+=x,ins(stu(i,j),T,x);
    		for (int i=1,x;i<=n;i++) for (int j=1;j<=m;j++){
    			scanf("%d",&x),sum+=x;
    			for (int k=0;k<5;k++){
    				int nx=i+dx[k],ny=j+dy[k];
    				if (nx<1||nx>n||ny<1||ny>m) continue;
    				ins(art(i,j),stu(nx,ny),inf);
    			}
    			ins(S,art(i,j),x);
    		}
    		for (int i=1,x;i<=n;i++) for (int j=1;j<=m;j++){
    			scanf("%d",&x),sum+=x;
    			for (int k=0;k<5;k++){
    				int nx=i+dx[k],ny=j+dy[k];
    				if (nx<1||nx>n||ny<1||ny>m) continue;
    				ins(stu(nx,ny),sci(i,j),inf);
    			}
    			ins(sci(i,j),T,x);
    		}
    	}
    	bool bfs(){
    		memset(dis,-1,sizeof(dis));
    		q[tail=1]=S,dis[S]=head=0;
    		while (head!=tail){
    			if (++head>maxn) head=1;
    			int x=q[head];
    			for (int y=now[x];y;y=pre[y])
    				if (val[y]&&dis[son[y]]==-1){
    					if (++tail>maxn) tail=1;
    					dis[son[y]]=dis[x]+1,q[tail]=son[y];
    				}
    		}
    		return dis[T]>0;
    	}
    	int find(int x,int low){
    		if (x==T) return low;
    		int y,res=0;
    		for (y=now[x];y;y=pre[y]){
    			if (dis[son[y]]!=dis[x]+1||!val[y]) continue;
    			int tmp=find(son[y],min(low,val[y]));
    			res+=tmp,low-=tmp,val[y]-=tmp,val[y^1]+=tmp;
    			if (!low) break;
    		}
    		if (!y) dis[x]=-1;
    		return res;
    	}
    	void work(){
    		while (bfs()) sum-=find(S,inf);
    		printf("%d
    ",sum);
    	}
    }F;
    
    int main(){
    	scanf("%d%d",&n,&m),F.init();
    	F.build(),F.work();
    	return 0;
    }



  • 相关阅读:
    Python—使用列表构造队列数据结构
    js数组及对象去重
    当z-index遇上transform
    echarts y轴百分比显示
    在vue-cli项目中使用echarts
    IE中在a标签里的图片会显示边框
    css 三种清除浮动(float)的方法
    js技巧
    深入理解 函数、匿名函数、自执行函数
    即时反应的input和propertychange方法
  • 原文地址:https://www.cnblogs.com/thythy/p/5493453.html
Copyright © 2020-2023  润新知