zoukankan      html  css  js  c++  java
  • 【BZOJ2095】【POI2010】Bridge 网络流

    题目大意

    ​  给你一个无向图,每条边的两个方向的边权可能不同。要求找出一条欧拉回路使得路径上的边权的最大值最小。无解输出"NIE"。
      (2leq nleq 1000,1leq mleq 2000)

    题解

    ​  我们先二分答案(ans),把边权大于(ans)的边删掉。

    ​  现在图中还剩下一些有向边和一些无向边,也就是说这是一个混合图。

    ​  混合图的欧拉回路怎么求?

    ​  先把无向边定向(方向任意),求出每个点的出度(d1_i)和入度(d2_i)。如果存在点(i)使得(|d1_i-d2_i|)为奇数,则无解。因为你怎么反向都不可能把(d1_i-d2_i)变成(0)

    ​  然后把无向边按定向的反方向在图中连边,容量为(1)。对于一个点(i),如果(d1_i>d2_i),则连边(i ext{->}T),容量为(frac{d1_i-d2_i}{2}),否则连边(S ext{->}i),容量为(frac{d2_i-d1_i}{2})

    ​  最后跑一次最大流。如果满流就有解,否则无解。

      还要用并查集判一下是不是连通图。

    ​  为什么这是对的?每流过一条边就表示把这条边反向。对这个网络求最大流就是调整尽可能多的边。流量平衡就表示一个点的入度和出度相同。

    这里写图片描述

    ​  这个图把边定向得到

    ​  这里写图片描述

    ​  建图后跑最大流可以得到

      这里写图片描述

    ​  把满流边反向后得到

      这里写图片描述

    ​  这就是一个欧拉回路了

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<ctime>
    #include<utility>
    #include<queue>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    struct list
    {
    	int v[100010];
    	int w[100010];
    	int t[100010];
    	int h[1010];
    	int n;
    	void clear()
    	{
    		memset(h,0,sizeof h);
    		n=0;
    	}
    	void add(int x,int y,int z)
    	{
    		n++;
    		v[n]=y;
    		w[n]=z;
    		t[n]=h[x];
    		h[x]=n;
    	}
    };
    list l;
    void add(int x,int y,int z)
    {
    	l.add(x,y,z);
    	l.add(y,x,0);
    }
    int d[1010];
    int S,T;
    int bfs()
    {
    	memset(d,-1,sizeof d);
    	queue<int> q;
    	q.push(S);
    	d[S]=0;
    	int x,i;
    	while(!q.empty())
    	{
    		x=q.front();
    		q.pop();
    		for(i=l.h[x];i;i=l.t[i])
    			if(l.w[i]&&d[l.v[i]]==-1)
    			{
    				d[l.v[i]]=d[x]+1;
    				if(l.v[i]==T)
    					return 1;
    				q.push(l.v[i]);
    			}
    	}
    	return 0;
    }
    int op(int x)
    {
    	return ((x-1)^1)+1;
    }
    int dfs(int x,int flow)
    {
    	if(x==T)
    		return flow;
    	int c,s=0,i;
    	for(i=l.h[x];i;i=l.t[i])
    		if(l.w[i]&&d[l.v[i]]==d[x]+1)
    		{
    			c=dfs(l.v[i],min(flow,l.w[i]));
    			s+=c;
    			flow-=c;
    			l.w[i]-=c;
    			l.w[op(i)]+=c;
    			if(!flow)
    				break;
    		}
    	return s;
    }
    int f[1010];
    int find(int x)
    {
    	return f[x]==x?x:f[x]=find(f[x]);
    }
    int lx[2010],ly[2010],w1[2010],w2[2010];
    int d1[2010],d2[2010];
    int c[2010];//方向 
    int n,m;
    int abs(int x)
    {
    	return x>0?x:-x;
    }
    int check(int p)
    {
    	memset(d1,0,sizeof d1);
    	memset(d2,0,sizeof d2);
    	int i;
    	for(i=1;i<=n;i++)
    		f[i]=i;
    	for(i=1;i<=m;i++)
    	{
    		if(p<w1[i]&&p<w2[i])
    			return 0;
    		if(p>=w1[i])
    		{
    			c[i]=0;
    			d1[lx[i]]++;
    			d2[ly[i]]++;
    			f[find(lx[i])]=find(ly[i]);
    		}
    		else
    		{
    			c[i]=1;
    			d1[ly[i]]++;
    			d2[lx[i]]++;
    			f[find(lx[i])]=find(ly[i]);
    		}
    	}
    	for(i=1;i<=n;i++)
    	{
    		if(abs(d1[i]-d2[i])&1)
    			return 0;
    		if(i>1&&find(i)!=find(i-1))
    			return 0;
    	}
    	l.clear();
    	S=n+1;
    	T=n+2;
    	for(i=1;i<=m;i++)
    		if(p>=w1[i]&&p>=w2[i])
    			add(ly[i],lx[i],1);
    //		else
    //			add(lx[i],ly[i],1);
    	int s=0,ans=0;
    	for(i=1;i<=n;i++)
    		if(d1[i]>d2[i])
    		{
    			add(i,T,(d1[i]-d2[i])/2);
    			s+=(d1[i]-d2[i])/2;
    		}
    		else if(d1[i]<d2[i])
    			add(S,i,(d2[i]-d1[i])/2);
    	while(bfs())
    		ans+=dfs(S,0x7fffffff);
    	return ans==s;
    }
    int main()
    {
    //	freopen("bzoj2095.in","r",stdin);
    	scanf("%d%d",&n,&m);
    	int i;
    	for(i=1;i<=m;i++)
    		scanf("%d%d%d%d",&lx[i],&ly[i],&w1[i],&w2[i]);
    	int l=1,r=1001;
    	int mid;
    	while(l<r)
    	{
    		mid=(l+r)>>1;
    		if(check(mid))
    			r=mid;
    		else
    			l=mid+1;
    	}
    	if(l>1000)
    		printf("NIE
    ");
    	else
    		printf("%d
    ",l);
    	return 0;
    }
    
  • 相关阅读:
    RSA使用
    C#获取主机信息
    NSIS打包软件使用
    C#获取局域网主机
    C#实现Web链接启动应用程序
    4.布局介绍
    Server Sql 多表查询、子查询和分页
    C# File类常用方法
    Vue 使用技巧手记
    前端面试题手记
  • 原文地址:https://www.cnblogs.com/ywwyww/p/8510609.html
Copyright © 2011-2022 走看看