zoukankan      html  css  js  c++  java
  • [国家集训队]happiness

    题目:洛谷P1646、BZOJ2127。

    题目大意:
    高一一班的座位表是个n*m的矩阵,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友。这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一对好朋友如果能同时选文科或者理科,那么他们又将收获一些喜悦值。求最大可能的喜悦值之和。
    解题思路:
    比较恶心的最小割。
    首先,从源点向每个人连容量为(选文科所得的喜悦值)的边,从每个人向汇点连容量为(选理科所得的喜悦值)。
    然后,对于相邻的两个人x和y,建一个新的点k,若他们都选文科,则从源点向k连容量为(产生的喜悦值)的边,再从k向x、y分别连容量为inf的边;若他们都选理科,则从k向汇点连容量为(产生的喜悦之)的边,再从x、y分别向k连容量为inf的边(不能理解的话可以话草图割一割)。
    跑最大流,然后用所有读入的喜悦值的总和减去最大流即可。

    C++ Code:

    #include<bits/stdc++.h>
    #define S 0
    #define T 600001
    #define inf 0x3f3f3f3f
    inline int readint(){
    	int c=getchar(),d=0;
    	for(;!isdigit(c);c=getchar());
    	for(;isdigit(c);c=getchar())
    	d=(d<<3)+(d<<1)+(c^'0');
    	return d;
    }
    struct edge{
    	int to,cap,nxt;
    }e[3000000];
    int n,m,head[600005],cnt=1,s=0,level[600005],iter[600005];
    inline int addedge(const int u,const int v,const int f){
    	e[++cnt]=(edge){v,f,head[u]};
    	head[u]=cnt;
    	e[++cnt]=(edge){u,0,head[v]};
    	head[v]=cnt;
    	if(f!=inf)
    	s+=f;
    }
    inline int num(const int x,const int y){return n*(y-1)+x;}
    std::queue<int>q;
    void bfs(){
    	q.push(S);
    	level[S]=1;
    	while(!q.empty()){
    		int u=q.front();q.pop();
    		for(int i=head[u];i!=-1;i=e[i].nxt)
    		if(e[i].cap&&level[e[i].to]==-1){
    			level[e[i].to]=level[u]+1;
    			q.push(e[i].to);
    		}
    	}
    }
    inline int min(const int a,const int b){return a<b?a:b;}
    int dfs(const int u,const int t,const int f){
    	if(f==0||u==t)return f;
    	for(int& i=iter[u];i!=-1;i=e[i].nxt)
    	if(e[i].cap&&level[e[i].to]==1+level[u]){
    		int d=dfs(e[i].to,t,min(e[i].cap,f));
    		if(d){
    			e[i].cap-=d;
    			e[i^1].cap+=d;
    			return d;
    		}
    	}
    	return 0;
    }
    int dinic(){
    	for(int f,flow=0;;){
    		memset(level,-1,sizeof level);
    		bfs();
    		if(level[T]==-1)return flow;
    		memcpy(iter,head,sizeof iter);
    		while(f=dfs(S,T,inf))flow+=f;
    	}
    }
    int main(){
    	n=readint(),m=readint();
    	memset(head,-1,sizeof head);
    	int CNT=n*m+1;
    	for(int i=1;i<=n;++i)
    	for(int j=1;j<=m;++j)addedge(S,num(i,j),readint());
    	for(int i=1;i<=n;++i)
    	for(int j=1;j<=m;++j)addedge(num(i,j),T,readint());
    	for(int i=1;i<n;++i)
    	for(int j=1;j<=m;++j){
    		int x=num(i,j),y=num(i+1,j);
    		addedge(++CNT,x,inf);
    		addedge(CNT,y,inf);
    		addedge(S,CNT,readint());
    	}
    	for(int i=1;i<n;++i)
    	for(int j=1;j<=m;++j){
    		int x=num(i,j),y=num(i+1,j);
    		addedge(x,++CNT,inf);
    		addedge(y,CNT,inf);
    		addedge(CNT,T,readint()); 
    	}
    	for(int i=1;i<=n;++i)
    	for(int j=1;j<m;++j){
    		int x=num(i,j),y=num(i,j+1);
    		addedge(++CNT,x,inf);
    		addedge(CNT,y,inf);
    		addedge(S,CNT,readint());
    	}
    	for(int i=1;i<=n;++i)
    	for(int j=1;j<m;++j){
    		int x=num(i,j),y=num(i,j+1);
    		addedge(x,++CNT,inf);
    		addedge(y,CNT,inf);
    		addedge(CNT,T,readint());
    	}
    	printf("%d
    ",s-dinic());
    	return 0;
    }
    
  • 相关阅读:
    蛇形矩阵
    润年还是平年
    汽水瓶
    魔幻矩阵
    魔方矩阵
    时间字段替换
    Windows Server 2012 R2蓝屏
    查询速度慢的原因很多(转载)
    索引和锁
    别不拿里程碑当石头---------IT项目管理之项目计划(转)
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/9123247.html
Copyright © 2011-2022 走看看