题目大意
给你一个无向图,每条边的两个方向的边权可能不同。要求找出一条欧拉回路使得路径上的边权的最大值最小。无解输出"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;elsel=mid+1;}if(l>1000)printf("NIE\n");elseprintf("%d\n",l);return 0;
}