zoukankan      html  css  js  c++  java
  • [51nod2935] 土地划分

    问题描述

    Y国有N座城市,并且有M条双向公路将这些城市连接起来,并且任意两个城市至少有一条路径可以互达。
    Y国的国王去世之后,他的两个儿子A和B都想成为新的国王,但他们都想让这个国家更加安定,不会用武力解决问题。
    于是他们想将这个国家分成两个小国家A国和B国。现在,A拥有1号城市,B拥有N号城市,其他的城市还尚未确定归属哪边(划分之后的国家内部城市可以不连通)。
    由于大家都想让国家变得更好,而某些城市的人民愿意国王的A儿子作为他们的领袖,而某些城市更看好B,而为了交通的便捷,如果划分后的公路连接两个同一个国家的城市,那么更利于城市之间的交流。于是大臣们设计了一种对土地划分的评分机制,具体如下:
    1. 对于城市i,如果它划分给A国,将得到VA[i]的得分;划分给B国,将得到VB[i]的得分。
    2. 对于一条公路i,如果它连接两个A国的城市,将得到EA[i]的得分;连接两个B国的城市,将得到EB[i]的得分;否则,这条公路将失去意义,将扣除EC[i]的得分。
    现请你找到最优的土地划分,使得这种它的评分最高。

    输入格式

    第一行包含两个整数N,M,含义如问题描述所示。
    接下来一行N-2个非负整数,表示VA[2..N-1]。
    接下来一行N-2个非负整数,表示VB[2..N-1]。
    接下来M行,每行五个非负整数描述一条公路:X Y EA[i] EB[i] EC[i],含义如问题描述所示。

    输出格式

    输出有且仅有一个整数,表示最高评分。

    样例输入

    3 3
    8
    9
    1 2 2 6 2
    2 3 8 5 7
    1 3 9 4 1

    样例输出

    11

    数据范围

    10% 2 <= N <= 20 2 <= M <= 70
    20% 2 <= N <= 20 2 <= M <= 150
    50% 2 <= N <= 2000 2 <= M <= 8000
    100% 2 <= N <= 10000 2 <= M <= 40000
    保证运算过程中及最终结果不超过32位带符号整数类型的表示范围

    解析

    考虑如何构造最小割模型。关键是割边的意义。

    首先,源点向一个点连容量为该点归A国的得分的边,同时这个点向汇点连容量为该点归B国的得分的边。这样就能保证一个点一定只会归属一个国家。特殊的,1号点只有和源点的边,n号点只有和汇点的边,容量均为无穷大。

    然后考虑边。一共有三种情况:边的两边都属于A,得到两个属于A的分数加上EA;边的两边都属于B,得到两个属于B的分数加上EB;以及两边各属于一个国家,付出EC的代价。要保证割边的方案只能一一对应这三种情况,对于边((u,v))我们可以这样构造:

    即将一条边拆成两个点。最后跑最大流求得最小割即可。

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <queue>
    #define N 1000002
    #define M 1000002
    using namespace std;
    const int inf=1<<30;
    int head[N],ver[M*2],nxt[M*2],cap[M*2],l;
    int n,m,s,t,i,dis[N],ans;
    int read()
    {
    	char c=getchar();
    	int w=0;
    	while(c<'0'||c>'9') c=getchar();
    	while(c<='9'&&c>='0'){
    		w=w*10+c-'0';
    		c=getchar();
    	}
    	return w;
    }
    void insert(int x,int y,int z)
    {
    	ver[l]=y;
    	cap[l]=z;
    	nxt[l]=head[x];
    	head[x]=l;
    	l++;
    	ver[l]=x;
    	nxt[l]=head[y];
    	head[y]=l;
    	l++;
    }
    bool bfs()
    {
    	queue<int> q;
    	memset(dis,-1,sizeof(dis));
    	q.push(s);
    	dis[s]=0;
    	while(!q.empty()){
    		int x=q.front();
    		q.pop();
    		for(int i=head[x];i!=-1;i=nxt[i]){
    			int y=ver[i];
    			if(dis[y]==-1&&cap[i]>0){
    				dis[y]=dis[x]+1;
    				q.push(y);
    			}
    		}
    	}
    	return (dis[t]!=-1);
    }
    int dfs(int x,int flow)
    {
    	if(x==t||flow==0) return flow;
    	int ans=0;
    	for(int i=head[x];i!=-1;i=nxt[i]){
    		int y=ver[i];
    		if(dis[y]==dis[x]+1&&cap[i]>0){
    			int a=dfs(y,min(flow,cap[i]));
    			flow-=a;
    			ans+=a;
    			cap[i]-=a;
    			cap[i^1]+=a;
    		}
    		if(flow==0) break;
    	}
    	if(flow) dis[x]=-1;
    	return ans;
    }
    int main()
    {
    	memset(head,-1,sizeof(head));
    	n=read();m=read();
    	t=n+2*m+1;
    	for(i=2;i<n;i++){
    		int va=read();
    		insert(s,i,va);
    		ans+=va;
    	}
    	for(i=2;i<n;i++){
    		int vb=read();
    		insert(i,t,vb);
    		ans+=vb;
    	}
    	insert(s,1,inf);
    	insert(n,t,inf);
    	for(i=1;i<=m;i++){
    		int u=read(),v=read(),ea=read(),eb=read(),ec=read();
    		insert(u,v,ec);insert(v,u,ec);
    		insert(s,n+i,ea);insert(n+i,u,inf);insert(n+i,v,inf);
    		insert(n+m+i,t,eb);insert(u,n+m+i,inf);insert(v,n+m+i,inf);
    		ans+=ea+eb;
    	}
    	while(bfs()) ans-=dfs(s,inf);
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    [Usaco2008 Nov]mixup2 混乱的奶牛
    [Poi2004] 旅行问题
    [洛谷P1278]单词游戏
    redis20
    redis19
    redis18
    OHC Java堆外缓存详解与应用
    SQL优化
    Mysql安装、字符、引擎设置
    大文件下载
  • 原文地址:https://www.cnblogs.com/LSlzf/p/12663171.html
Copyright © 2011-2022 走看看