Loj#2460-「POI2010」桥Bridges【网络流,欧拉回路】

1|0正题

题目链接:https://loj.ac/p/2460


1|1题目大意

给出n个点m条边的一张无向图,每条边双向的权值不同,求一条经过的最大权值最小的欧拉回路。

2n1000,1m20000


1|2解题思路

显然我们可以二分答案,考虑二分答案后我们怎么做。

不妨设权值小的那个方向为默认方向,那这样我们可以处理出一个入度-出度的数组deg

此时我们翻转一条边可以让头的deg移动2到尾处,那么做法就很显然了。

如果度数有奇数直接无解,否则我们用网络流连接能翻转的边去配平deg

得到一个答案后我们就可以根据残余网络得到一张有欧拉回路的有向图了。

然后就是有向图的欧拉回路,发现我们如果随机走一条路出去的话此时可能会走到死路。

但是注意到如果一个位置是死路那么之前我们肯定来过至少一次这里。那么做法就是我们正常的遍历没有走过的边,到死路时我们回退回去,类似于正常的dfs可以继续搜其他的路。

此时我们就可以合并我们伸出的两条路,反过来记录和输出遍历的边就好了


1|3code

#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<stack> #define mp(x,y) make_pair(x,y) using namespace std; const int M=2e4+1e3,N=1e3+10; int n,m,s,t,tot,S,fa[N],p[M]; int deg[N],ls[N],dep[N]; queue<int> q;stack<int> st; queue<pair<int,int> >G[N]; struct edge{ int to,next,w; }a[M*4]; struct node{ int x,y,w; }e[M]; void addl(int x,int y,int w){ a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w; a[++tot].to=x;a[tot].next=ls[y];ls[y]=tot;a[tot].w=0; return; } bool bfs(){ while(!q.empty())q.pop();q.push(s); memset(dep,0,sizeof(dep));dep[s]=1; while(!q.empty()){ int x=q.front();q.pop(); for(int i=ls[x];i;i=a[i].next){ int y=a[i].to; if(!a[i].w||dep[y])continue; dep[y]=dep[x]+1; if(y==t)return 1; q.push(y); } } return 0; } int dinic(int x,int flow){ if(x==t)return flow; int rest=0,k; for(int i=ls[x];i;i=a[i].next){ int y=a[i].to; if(dep[x]+1==dep[y]&&a[i].w){ rest+=(k=dinic(y,min(a[i].w,flow-rest))); a[i].w-=k;a[i^1].w+=k; if(rest==flow)return rest; } } if(!rest)dep[x]=0; return rest; } int find(int x) {return (fa[x]==x)?x:(fa[x]=find(fa[x]));} int check(int w){ memset(ls,0,sizeof(ls));tot=1; for(int i=1;i<=n;i++){ if(deg[i]>0)addl(s,i,deg[i]/2); if(deg[i]<0)addl(i,t,-deg[i]/2); } for(int i=1;i<=m;i++) if(e[i].w<=w) addl(e[i].x,e[i].y,1),p[i]=tot; int ans=0; while(bfs()) ans+=dinic(s,1e9); return (ans==S); } void dfs(int x){ while(!G[x].empty()){ int y=G[x].front().first; int k=G[x].front().second; G[x].pop();dfs(y); st.push(k); } return; } int main() { // freopen("euler.in","r",stdin); // freopen("euler.out","w",stdout); scanf("%d%d",&n,&m);s=n+1;t=n+2; for(int i=1;i<=n;i++)fa[i]=i; int k=n,L=0,R=0; for(int i=1;i<=m;i++){ int x,y,v1,v2; scanf("%d%d%d%d",&x,&y,&v1,&v2); if(v1>v2)swap(x,y),swap(v1,v2); if(find(x)!=find(y)) fa[find(x)]=find(y),k--; L=max(L,v1);R=max(R,v2); e[i]=(node){y,x,v2}; deg[x]--;deg[y]++; } if(k!=1)return puts("NIE")&0; for(int i=1;i<=n;i++) if(deg[i]&1)return puts("NIE")&0; else if(deg[i]>0) S+=deg[i]/2; int lim=R; while(L<=R){ int mid=(L+R)>>1; if(check(mid))R=mid-1; else L=mid+1; } if(L>lim)return puts("NIE")&0; check(L); printf("%d\n",L); for(int i=1;i<=m;i++){ if(e[i].w<=L){ if(a[p[i]].w)G[e[i].x].push(mp(e[i].y,i)); else G[e[i].y].push(mp(e[i].x,i)); } else G[e[i].y].push(mp(e[i].x,i)); } dfs(1); while(!st.empty()) printf("%d ",st.top()),st.pop(); return 0; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/15869219.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(61)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
历史上的今天:
2021-02-07 P4338-[ZJOI2018]历史【LCT】
2021-02-07 P3760-[TJOI2017]异或和【树状数组】
2021-02-07 P3273-[SCOI2011]棘手的操作【线段树,并查集】
2021-02-07 P4424-[HNOI/AHOI2018]寻宝游戏【结论】
2021-02-07 P4606-[SDOI2018]战略游戏【圆方树,虚树】
点击右上角即可分享
微信分享提示