传送门php
这篇题解讲的真吼->这里html
首先咱们能够二分一个答案,而后把全部权值小于这个答案的都加入图中ios
那么问题就转化为一张混合图(既有有向边又有无向边)中是否存在欧拉回路git
首先网络
无向图存在欧拉回路,当且仅当图的全部顶点度数都为偶数且图连通。spa
有向图存在欧拉回路,当且仅当图的全部顶点入度等于出度且图连通。code
那么咱们怎么判断混合图的欧拉回路是否存在呢?htm
咱们把无向边的边随便定向,而后计算每个点的入度和出度。若是有某一个点的入度和出度之差是奇数,那么确定不存在欧拉回路。blog
由于欧拉回路要求入度等于出度,也就是总度数为偶数,因此有奇数度点确定不存在欧拉回路get
那么如今每一个点的入度和出度之差都是偶数,咱们把它除以二,设为$x$,那么,对于每个点,咱们只要改变与它相连的$x$条边的方向改变,它就能保证入度等于出度。若是每一个点都能这样,那么这张图就存在一个欧拉回路
那么咱们该改变哪些边来让点的出度等于入度呢?首先,有向边不能改变,忽略。而后咱们一开始不是把无向边定向了么?那咱们就按照定的向构建网络,边长容量$1$。而后新建源点和汇点,若是入度大于出度,则将点向汇点连边,容量为$x$,若是出度大于入度,则将源点向该点连边,容量为$x$。而后咱们只要跑一个最大流,看看可否使网络满流。若能够,则有解,不然无解
考虑为何。咱们把网络中每一条满流的边(也就是流量非0的边)反向,就能获得一个每点入度等于出度的欧拉图。由于这个网络满流,因此每个入度大于出度的点都会有$x$条边进来,把这$x$条边反向就能使它入度等于出度。出度大于入度的点同理。那么,既没和源点连也没和汇点连的点怎么办呢?由于这样的点一定是入度等于出度的,那么在网络流过程当中他们属于中间点,那么一定知足流量守恒,因此进来的流量和出去的流量是同样的,那么反向以后仍然保持平衡
解决了
1 //minamoto 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #include<queue> 7 #define inf 0x3f3f3f3f 8 using namespace std; 9 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 10 char buf[1<<21],*p1=buf,*p2=buf; 11 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;} 12 template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;} 13 inline int read(){ 14 #define num ch-'0' 15 char ch;bool flag=0;int res; 16 while(!isdigit(ch=getc())) 17 (ch=='-')&&(flag=true); 18 for(res=num;isdigit(ch=getc());res=res*10+num); 19 (flag)&&(res=-res); 20 #undef num 21 return res; 22 } 23 const int N=5005,M=100005; 24 int head[N],Next[M],ver[M],edge[M],tot; 25 int out[N],in[N],u[N],v[N],w1[N],w2[N],sum; 26 int dep[N],cur[N]; 27 int n,m,s,t; 28 queue<int> q; 29 inline void add(int u,int v,int e){ 30 ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=e; 31 ver[++tot]=u,Next[tot]=head[v],head[v]=tot,edge[tot]=0; 32 } 33 bool bfs(){ 34 memset(dep,-1,sizeof(dep)); 35 while(!q.empty()) q.pop(); 36 for(int i=s;i<=t;++i) cur[i]=head[i]; 37 q.push(s),dep[s]=0; 38 while(!q.empty()){ 39 int u=q.front();q.pop(); 40 for(int i=head[u];i;i=Next[i]){ 41 int v=ver[i]; 42 if(dep[v]<0&&edge[i]){ 43 dep[v]=dep[u]+1,q.push(v); 44 if(v==t) return true; 45 } 46 } 47 } 48 return false; 49 } 50 int dfs(int u,int limit){ 51 if(u==t||!limit) return limit; 52 int flow=0,f; 53 for(int i=cur[u];i;i=Next[i]){ 54 int v=ver[i];cur[u]=i; 55 if(dep[v]==dep[u]+1&&(f=dfs(v,min(limit,edge[i])))){ 56 flow+=f,limit-=f; 57 edge[i]-=f,edge[i^1]+=f; 58 if(!limit) break; 59 } 60 } 61 if(!flow) dep[u]=-1; 62 return flow; 63 } 64 int dinic(){ 65 int flow=0; 66 while(bfs()) flow+=dfs(s,inf); 67 return flow; 68 } 69 bool check(int mid){ 70 memset(head,0,sizeof(head)),tot=1; 71 memset(out,0,sizeof(out)); 72 memset(in,0,sizeof(in)); 73 sum=0; 74 for(int i=1;i<=m;++i){ 75 if(w1[i]<=mid) ++out[u[i]],++in[v[i]];//有向边记入度和出度 76 if(w2[i]<=mid) add(u[i],v[i],1);//无向边随便定个方向 77 } 78 for(int i=1;i<=n;++i) if(abs(in[i]-out[i])&1) return false; 79 for(int i=1;i<=n;++i){ 80 int x=in[i]-out[i]; 81 sum+=x>0?x>>1:0; 82 if(x>0) add(i,t,x>>1); 83 if(x<0) add(s,i,(-x)>>1); 84 } 85 return dinic()==sum; 86 } 87 int main(){ 88 //freopen("testdata.in","r",stdin); 89 n=read(),m=read(),s=0,t=n+1; 90 int l=inf,r=-inf; 91 for(int i=1;i<=m;++i){ 92 u[i]=read(),v[i]=read(),w1[i]=read(),w2[i]=read(); 93 if(w1[i]>w2[i]) swap(u[i],v[i]),swap(w1[i],w2[i]); 94 cmin(l,w1[i]),cmax(r,w2[i]); 95 } 96 while(l<=r){ 97 int mid=l+r>>1; 98 if(check(mid)) r=mid-1;else l=mid+1; 99 } 100 if(!check(l)) puts("NIE");else printf("%d\n",l); 101 return 0; 102 } 103 ?