【XSY2024】【BZOJ2095】【POI2010】Bridge 网络流

来源:互联网 发布:数据新闻报道方向 编辑:程序博客网 时间:2024/06/05 20:40

题目大意

​  给你一个无向图,每条边的两个方向的边权可能不同。要求找出一条欧拉回路使得路径上的边权的最大值最小。无解输出”NIE”。
  2n1000,1m2000

题解

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

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

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

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

​  然后把无向边按定向的反方向在图中连边,容量为1。对于一个点i,如果d1i>d2i,则连边i->T,容量为d1id2i2,否则连边S->i,容量为d2id1i2

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

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

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

这里写图片描述

​  这个图把边定向得到

​  这里写图片描述

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

  这里写图片描述

​  把满流边反向后得到

  这里写图片描述

​  这就是一个欧拉回路了

代码

#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;}