【BZOJ2095】【POI2010】Bridge 网络流


题目大意

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

题解

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

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

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

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

​  然后把无向边按定向的反方向在图中连边,容量为\(1\)。对于一个点\(i\),如果\(d1_i>d2_i\),则连边\(i\text{->}T\),容量为\(\frac{d1_i-d2_i}{2}\),否则连边\(S\text{->}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\n");
    else
        printf("%d\n",l);
    return 0;
}
优质内容筛选与推荐>>
1、如何摆脱节后综合症
2、21天学通C++_Day4
3、Proving Equivalences UVA - 12167
4、Haddoop中的hdfs、hbase、 hive区别与联系
5、设计模式三: 代理模式(Proxy) -- JDK的实现方式


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号