图论欧拉回路初步 BZOJ2095 POI2010 Bridges
反正对于现在的我来说是好题。顺便膜po大犇和dingchao大犇。
网络流什么的还是再开一个专题好了。
欧拉回路问题参考论文《欧拉回路性质与应用探究》by 仇荣琦。
POI2010 题解整理
Description
小C为了减肥,他来到了瘦海,这是一个巨大的海,海中有n个小岛,小岛之间有m座桥连接,两个小岛之间不会有两座桥,并且从一个小岛可以到另外任意一个小岛。
现在小C想骑单车从小岛1出发,骑过每一座桥,到达每一个小岛,然后回到小岛1。小Q为了让小C减肥成功,召唤了大风,由于是海上,风变得十分大,经过每一座桥都有不可避免的风阻碍小C。小C十分ddt,于是用泡芙贿赂了你,希望你能帮他找出一条承受的最大风力最小的路线。
注意的是每条边能且只能经过一次,即欧拉回路。
Input
- Line 1:两个为空格隔开的整数nn,mm。
- Line 2~m+1:每行由空格隔开的4个整数aa,bb,cc,dd组成,表示第i+1i+1行第ii座桥连接小岛aa和bb,从aa到bb承受的风力为cc,从bb到aa承受的风力为dd。
- 【数据范围】:
- 1≤m≤2000,2≤n≤10001\le m\le 2000,2\le n\le1000。
- 1≤a≠b≤n,1≤c,d≤10001\le a\neq b\le n,1\le c,d\le 1000。
Sample Input
4 4
1 2 2 4
2 3 3 4
3 4 4 4
4 1 5 4Output
如果无法完成减肥计划,则输出NIE;
否则第一行输出最小的承受风力的最大值,且第二行输出一份方案(输出的是边的编号,第i+1i+1行对应编号ii)。
Sample Output
4
4 3 2 1Output Details
样例如图所示:
首先这一题套在外面的二分答案是非常明显的,怎么说题目中也频繁出现了“最大值最小”之类的字眼。二分枚举这个最大风力,那么我们可以把剩下的图提取出来。
根据题意要求:每条边必须经过一次,而点可以多次经过,并且最后要回到原点。这样的定义指向欧拉回路。于是本题的任务变成:
- 对于重构的混合图(既包含有向边又包含无向边)进行欧拉回路判定,再输出对于最小符合题意风力重构的图的欧拉回路方案。
图论欧拉回路初步:
引入:(我这引入也真TM有个性)
NOIP初赛有这样一道题目:
[NOIP2007 提高组初赛 T9]欧拉图GG是指可以构成一个闭回路的图,且图GG的每一条边恰好在这个闭回路上出现一次(即一笔画成)。在以下各个描述中,不一定是欧拉图的是(D)。
- A. 图GG中没有度为奇数的顶点 。
- B. 包含欧拉环游的图。
- C. 包含欧拉闭迹的图。
- D. 存在一条回路,通过每个顶点恰好一次。
- E. 本身为闭迹的图。
欧拉回路的基本概念(顺便解决上述问题):设图G=(V,E)G=(V,E)。
- 欧拉路径(欧拉迹):图GG中经过每条边一次并且仅一次的路径成为欧拉路径。
- 欧拉回路(欧拉闭迹):图GG中经过每条边一次并且仅一次的回路成为欧拉路径。
- 欧拉图:存在欧拉回路的图称为欧拉图。
- 半欧拉图:存在欧拉路径但不存在欧拉回路的图称为半欧拉图。
注意D选项是错误的。(哈密顿图:通过图GG的每个结点有且只有一次的回路,就是哈密顿回路,存在哈密顿回路的图就是哈密顿图)
欧拉图的判定定理:
- 无向图GG为欧拉图,当且仅当GG为连通图,且所有顶点的度为偶数。
- 有向图GG为欧拉图,当且仅当GG的基图连通,且所有顶点的入度等于出度。
欧拉图的性质:
- 设CC是欧拉图GG中的一个简单回路,将CC中的边从图GG中删去得到一个新的图G′G’,则G′G’的每个极大连通子图都有一条欧拉回路。(极大/小连通图:对于一个连通图来说,极大连通图即它本身,而极小连通图指这个连通图的生成树)
- 设C1C_1,C2C_2是图GG的两个没有公共边,但至少有一个公共顶点的简单回路,我们可以将其合并成一个新的简单回路C′C'。
1)求欧拉回路
根据上述性质,得到求欧拉回路的算法(注意是在欧拉图上):
- 在图GG中任意找到一个回路CC。
- 将图GG中属于回路CC的边删除。
- 在残留图的各极大子图中分别寻找欧拉回路。
- 将各极大连通子图的欧拉回路合并到CC中得到图GG的欧拉回路。
void Euler u //伪代码while(next v)if e(u,v) unmarked mark e(u,v),e(v,u)Euler vstack.push e(u,v)
上述伪代码的时间复杂度O(E)O(E),由于边数过多会有爆栈危险,我们也会采用非递归形式。(待添加)
- 以上内容引自《欧拉回路性质与应用探究》by 仇荣琦。
2)混合路欧拉路径判定
对每条无向边进行随机定向。
通过随机定边,我们暂时构造出了一个有向图,根据上述欧拉回路的有向图判定定理,我们在接下来的处理中只要通过调整该有向图中由无向边变成的有向边的方向,使得所有节点的入度=出度即可。
对当前的新图构建网络。
我们按照当前点的出入度进行建边:
假设该点的degree=u+−u−degree={u^+-u^-},degree>0degree>0表示需要更改从它连出去的degreedegree条边,同理degree<0degree表示需要更改从它连出去的−degree-degree条边。
再定义e(u,v,1)e(u,v,1)表示有值为1的流从uu向vv流出,此时edge(u,v)edge(u,v)被反向。同理,我们对于一个degree>0degree>0的点,为了让其degreedegree减小,我们假设一个虚拟源点SS,此时若e(S,u,degree2)e(S,u,\frac{degree}{2})中的流量能全部跑光,则说明uu后面的边可以通过修改方向,使得uu的出度=入度。
那么我们对按照以下方式建边:
- 所有degree>0degree>0的点从SS出发建边,所有degree<0degree的点向TT建边。
- 如果对于如果确定一条无向边的方向为edge(u,v)edge(u,v),则建一条(v,u,1)(v,u,1)的边。
跑最大流算法,检查是否满流。(最大流初步)(待补充)
检查是否满流时,按照上述定义只需要判断所有与S相连的边上是否满流即可。
CodeCode:(
请无视我因为取名癌把我男神名字丢结构体名称的举动)#include <bits/stdc++.h> #define M 2005 #define S 0 #define T 2004 #define inf 0x3f3f3f3f using namespace std; int n,m; struct edge{int u,v,w1,w2,id;}Edges[M];struct Union_Find_Set{int fa[M],cnt;void Init(){for(int i=1;i<=n;i++)fa[i]=i;cnt=n;}int Getfa(int x){return (fa[x]==x)?fa[x]:fa[x]=Getfa(fa[x]);}void Union(int u,int v){u=Getfa(u),v=Getfa(v);if(u!=v)fa[u]=v,cnt--;} }Emiya;//判断重构图是否为连通图struct Max_Flow{struct node{int v,f,nxt,id;}Nodes[M*M];int head[M],tot,degree[M],level[M];void Init(){memset(head,-1,sizeof(head));memset(degree,0,sizeof(degree));tot=1;}void Add_edge(int u,int v,int w,int id){Nodes[++tot]=(node){v,w,head[u],id};head[u]=tot;Nodes[++tot]=(node){u,0,head[v],id};head[v]=tot;}//邻接表bool bfs(){memset(level,-1,sizeof(level));level[S]=1;queue<int>Q;Q.push(S);while(!Q.empty()){int u=Q.front();Q.pop();for(int j=head[u];~j;j=Nodes[j].nxt)if(Nodes[j].f&&!~level[Nodes[j].v]){level[Nodes[j].v]=level[u]+1;Q.push(Nodes[j].v);if(Nodes[j].v==T)return true;}}return false;}int Dinic(int u,int flow){if(u==T)return flow;int left=flow;for(int j=head[u];~j&&left;j=Nodes[j].nxt)if(Nodes[j].f&&level[u]+1==level[Nodes[j].v]){int tmp=Dinic(Nodes[j].v,min(left,Nodes[j].f));if(tmp){left-=tmp;Nodes[j].f-=tmp;Nodes[j^1].f+=tmp;}}if(left)level[u]=-1;return flow-left;}//最大流Dinic算法,Ford_Fulkerson或Edmonds_Karp算法亦可以套用bool judge(int val){Emiya.Init();Init();for(int i=1;i<=m;i++){int u=Edges[i].u,v=Edges[i].v;if(Edges[i].w2<=val){//degree_in +1 degree_out -1 Emiya.Union(u,v);Add_edge(u,v,1,Edges[i].id);degree[u]++;degree[v]--;}else if(Edges[i].w1<=val){Emiya.Union(u,v);degree[u]--;degree[v]++;}}if(Emiya.cnt>1)return false;//原图不连通 for(int i=1;i<=n;i++){if(degree[i]&1)return false;//不满足欧拉回路性质if(degree[i]>0)Add_edge(S,i,degree[i]>>1,S);else if(degree[i]<0)Add_edge(i,T,-degree[i]>>1,T);}while(bfs())Dinic(S,inf);//使劲跑网络流,如果构成满流则说明找到了欧拉回路 for(int j=head[S];~j;j=Nodes[j].nxt)if(Nodes[j].f)return false;return true;} }Shirou;int bisection(int R){int L=1,res=-1;while(L<=R){int mid=L+R>>1;if(Shirou.judge(mid)){//跑欧拉回路 R=mid-1;res=mid;}else L=mid+1;}return res; }int head[M],tot=0; struct New_Graph{int v,nxt,id;bool vis;}Graph[M<<1]; void Add_New_Edge(int u,int v,int id){Graph[++tot]=(New_Graph){v,head[u],id,0};head[u]=tot; } bool f=false; stack<int>stk; void Euler_Print(int u){for(int j=head[u];~j;j=Graph[j].nxt){if(!Graph[j].vis){Graph[j].vis=true;Euler_Print(Graph[j].v);stk.push(Graph[j].id);}} }//打印解部分int main(){int num=0;scanf("%d %d",&n,&m);for(int i=1;i<=m;i++){int u,v,w1,w2;scanf("%d %d %d %d",&u,&v,&w1,&w2);if(w1>w2)swap(u,v),swap(w1,w2); Edges[i]=(edge){u,v,w1,w2,i};if(num<w1)num=w1;if(num<w2)num=w2;}int ans=bisection(num);//二分枚举当前的最大风力 if(!~ans)puts("NIE");else{printf("%d\n",ans);Shirou.judge(ans);memset(head,-1,sizeof(head));for(int i=1;i<=m;i++)//没有扔进网络流的单向边if(Edges[i].w2>ans&&Edges[i].w1<=ans)Add_New_Edge(Edges[i].u,Edges[i].v,Edges[i].id);for(int u=1;u<=n;u++)//网络流跑出来的满流边for(int j=Shirou.head[u];~j;j=Shirou.Nodes[j].nxt){Max_Flow::node now=Shirou.Nodes[j];if(!now.f&&now.v!=S&&now.v!=T)Add_New_Edge(u,now.v,now.id);}Euler_Print(1);while(!stk.empty()){printf("%d%c",stk.top(),stk.size()==1?'\n':' ');stk.pop();}puts("");}return 0; }
图论欧拉回路初步 BZOJ2095 POI2010 Bridges相关推荐
- BZOJ2095 POI2010 Bridges 【二分+混合图欧拉回路】
BZOJ2095 POI2010 Bridges Description YYD为了减肥,他来到了瘦海,这是一个巨大的海,海中有n个小岛,小岛之间有m座桥连接,两个小岛之间不会有两座桥,并且从一个小岛 ...
- BZOJ2095[Poi2010] Bridges
BZOJ2095[Poi2010] Bridges Description YYD为了减肥,他来到了瘦海,这是一个巨大的海,海中有n个小岛,小岛之间有m座桥连接,两个小岛之间不会有两座桥,并且从一个小 ...
- [BZOJ2095][Poi2010]Bridges 最大流(混合图欧拉回路)
2095: [Poi2010]Bridges Time Limit: 10 Sec Memory Limit: 259 MB Description YYD为了减肥,他来到了瘦海,这是一个巨大的海, ...
- Bzoj2095:[Poi2010]Bridges:混合图欧拉回路,网络流
题目链接:2095:[Poi2010]Bridges 二分答案建图后显然是混合图的欧拉回路,有向边删掉无向边随机定向计算入度-出度的差du[i],如果du[i]<0连边(i,T,-du[i]/2 ...
- bzoj2095 [Poi2010]Bridges
bzoj [Poi2010]Bridges Description YYD为了减肥,他来到了瘦海,这是一个巨大的海,海中有n个小岛,小岛之间有m座桥连接,两个小岛之间不会有两座桥,并且从一个小岛可以到 ...
- bzoj2095: [Poi2010]Bridges 二分+最大流
想当年第一次看到这个题是在**p的一套模拟题里?然后当时想过二分也想过最大流.然后就是没有想到一块,最后知道做法后就不了了之了. #include <iostream> #include ...
- BZOJ 2095: [Poi2010]Bridges 混合图欧拉回路
YYD为了减肥,他来到了瘦海,这是一个巨大的海,海中有n个小岛,小岛之间有m座桥连接,两个小岛之间不会有两座桥,并且从一个小岛可以到另外任意一个小岛.现在YYD想骑单车从小岛1出发,骑过每一座桥,到达 ...
- BZOJ 2095 [POI2010]Bridges (最大流、欧拉回路)
洛谷上有这题,但是输出方案缺SPJ..(而且我也懒得输出方案了) 题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2095 题解: 首先判 ...
- 2095: [Poi2010]Bridges 二分+混合图欧拉回路(网络流)
好厉害的题啊QAQ,并不会做. 最大值最小想到是二分,然后就是一个混合图欧拉回路的问题. 混合图欧拉回路问题的解决: 我们首先想到有向图的欧拉回路,需满足的条件是每个点的入度等于出度.那么对于一个混合 ...
最新文章
- 机器学习入门(02)— 由感知机到神经网络的过渡进化,激活函数在神经网络中的作用
- 大型网站技术架构(2):架构要素和高性能架构
- mysql union后面查不出_mysql – 多个UNION查询不起作用
- SpingBoot 整合 kafka Elk
- 什么是java socket_java 网络编程,Socket编程
- html css:背景图片链接css写法
- AI人工智能技术可以做什么
- Android开发案例 点击按钮出现 简易的消息提示框
- JavaScript高级程序设计(第三版)阅读笔记
- VB NetShare
- Docker安装phpmyadmin
- 2022年高压电工操作证考试题库及答案
- JAVA Applet——绘制心形曲线
- 关于1 problem (1 error, 0 warnings) 1 error and 0 warnings potentially fixable with the `--fix` 错误
- web项目bug总结
- 一些Mac OS X的使用技巧
- 迈阿密大学的计算机系咋样,迈阿密大学牛津分校计算机专业如何?过来人告诉你...
- 免费的 AI 动作捕捉工具 #Rokoko Video
- 机器学习中的数学——常用概率分布(二):范畴分布(Multinoulli分布)
- 我模拟了一个机器人后,对分层思想的更多感受