Ybtoj #584. 「網路流」歐拉回路
阿新 • • 發佈:2022-02-07
題面傳送門
首先看到最大值最小肯定就是二分答案。
考慮二分答案後只保留小於等於該答案的邊。如果有一條邊正向和逆向都被捨去了那麼肯定是無法形成歐拉回路的。
現在剩下了一些已經被定向的邊和方向不定的邊。
我們將方向不定的邊任意定向之後計算每個點的入度減去出度\(W_i\),眾所周知一個有向圖有歐拉回路的條件是任意\(W_i=0\),如果一個點的\(W_i\)為偶數,那麼一定不能為\(0\)。
現在有一些點的\(W\)為正,一些為負,則需要讓一些邊反向來使得所有\(W\)被調整成\(0\)
如果一條邊原本從\(x\)指向\(y\),則反向後,會使\(W_y\)減少\(2\),使\(W_x\)增加\(2\)
所以可以建出網路流圖:令所有反向邊流量為\(1\),同時從\(S\)指向每個\(W_i>0\)的點,權值為\(\frac{W_i}{2}\),\(W_i<0\)的點指向\(T\),權值為\(-\frac{W_i}{2}\)
跑一遍最大流就可以知道是否有解。輸出方案只要確定每一條邊的方向然後跑一遍有向圖歐拉回路即可。
時間複雜度\(O(能過\times \log V)\)
code:
#include<bits/stdc++.h> #define I inline #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) #define abs(x) ((x)>0?(x):-(x)) #define re register #define RI re int #define ll long long #define db double #define lb long db #define N 1000 #define M 20000 #define mod 998244353 #define Mod (mod-1) #define eps (1e-5) #define U unsigned int #define it iterator #define Gc() getchar() #define Me(x,y) memset(x,y,sizeof(x)) #define d(x,y) (m*x+(y)) #define R(n) (rand()*rand()%(n)+1) #define Pc(x) putchar(x) using namespace std; int n,m,x,S,T,l,r,mid,vis[M+5],st[M+5],H,In[N+5],Fl[M+5],X[M+5],Y[M+5],Z1[M+5],Z2[M+5]; struct yyy{int to,w,z;}tmp;struct ljb{int head,h[N+5];yyy f[M+5<<1];I void add(int x,int y,int z){f[++head]=(yyy){y,z,h[x]};h[x]=head;}}s,g; I void con(int x,int y,int z){s.add(x,y,z);s.add(y,x,0);} namespace Dicnic{ int S,T,ToT,d[N+5],Ns[N+5];queue<int> Q;I int BFS(){ RI i;while(!Q.empty()) Q.pop();Q.push(S);Me(d,0x3f);d[S]=0;Ns[S]=s.h[S];while(!Q.empty()) for(x=Q.front(),Q.pop(),i=s.h[x];i;i=tmp.z){ tmp=s.f[i];if(!tmp.w||d[tmp.to]<1e9) continue;d[tmp.to]=d[x]+1;Ns[tmp.to]=s.h[tmp.to];Q.push(tmp.to);if(tmp.to==T) return 1; }return 0; } I int DFS(int x,int Sum){ if(x==T)return Sum;RI i,pus=0,k;yyy tmp;for(i=Ns[x];i;i=tmp.z){ Ns[x]=i;tmp=s.f[i];if(!tmp.w||d[tmp.to]!=d[x]+1) continue;k=DFS(tmp.to,min(tmp.w,Sum));if(!k) d[tmp.to]=1e9;Sum-=k;pus+=k;s.f[i].w-=k;s.f[i^1].w+=k;if(!Sum) break; }return pus; } I int calc(){S=0;T=n+1;ToT=0;while(BFS()) ToT+=DFS(S,1e9);return ToT;} } I int check(int mid){ RI i;Me(In,0);for(i=1;i<=m;i++) { if(Z1[i]<=mid) Z2[i]<=mid?(In[Y[i]]++,In[X[i]]--):(In[Y[i]]++,In[X[i]]--); else if(Z2[i]<=mid)In[X[i]]++,In[Y[i]]--;else return 0; }int d=0; Me(s.h,0);s.head=1;S=0;T=n+1;for(i=1;i<=n;i++) if(In[i]&1) return 0;for(i=1;i<=n;i++) In[i]>0?(d+=In[i]/2,con(S,i,In[i]/2)):con(i,T,-In[i]/2); for(i=1;i<=m;i++) Z1[i]<=mid&&Z2[i]<=mid&&(con(Y[i],X[i],1),0);d-=Dicnic::calc();return !d; } I void dfs(int x){yyy tmp;for(RI i=s.h[x];i;i=tmp.z) tmp=s.f[i],!vis[tmp.w]&&(vis[tmp.w]=1,dfs(tmp.to),st[++H]=tmp.w);} I void GA(int mid){ RI i;Me(In,0);for(i=1;i<=m;i++) { if(Z1[i]<=mid) Z2[i]<=mid?(In[Y[i]]++,In[X[i]]--):(In[Y[i]]++,In[X[i]]--); else if(Z2[i]<=mid)In[X[i]]++,In[Y[i]]--; }int d=0; Me(s.h,0);s.head=1;S=0;T=n+1;for(i=1;i<=n;i++) In[i]>0?(d+=In[i]/2,con(S,i,In[i]/2)):con(i,T,-In[i]/2); for(i=1;i<=m;i++) Z1[i]<=mid&&Z2[i]<=mid&&(con(Y[i],X[i],1),Fl[i]=s.head-1,0);d-=Dicnic::calc(); for(i=1;i<=m;i++){ if(Z1[i]<=mid) Z2[i]<=mid?(s.f[Fl[i]].w?g.add(X[i],Y[i],i):g.add(Y[i],X[i],i)):(g.add(X[i],Y[i],i)); else if(Z2[i]<=mid) g.add(Y[i],X[i],i); }s=g;dfs(1);while(H) printf("%d ",st[H--]); } int main(){ freopen("euler.in","r",stdin);freopen("euler.out","w",stdout); RI i;scanf("%d%d",&n,&m);for(i=1;i<=m;i++) scanf("%d%d%d%d",&X[i],&Y[i],&Z1[i],&Z2[i]); l=0;r=1001;while(l+1<r) mid=l+r>>1,(check(mid)?r:l)=mid;if(r==1001) {puts("NIE");return 0;}printf("%d\n",r);GA(r); }