混合图的欧拉路径和欧拉回路判断
生活随笔
收集整理的這篇文章主要介紹了
混合图的欧拉路径和欧拉回路判断
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
混合圖(既有有向邊又有無向邊的圖)中歐拉環(huán)、歐拉路徑的判定需要借助網(wǎng)絡(luò)流!(1)歐拉環(huán)的判定:
一開始當(dāng)然是判斷原圖的基圖是否連通,若不連通則一定不存在歐拉環(huán)或歐拉路徑(不考慮度數(shù)為0的點(diǎn))。其實(shí),難點(diǎn)在于圖中的無向邊,需要對(duì)所有的無向邊定向(指定一個(gè)方向,使之變?yōu)橛邢蜻?#xff09;,使整個(gè)圖變成一個(gè)有向歐拉圖(或有向半歐拉圖)。若存在一個(gè)定向滿足此條件,則原圖是歐拉圖(或半歐拉圖)否則不是。關(guān)鍵就是如何定向?首先給原圖中的每條無向邊隨便指定一個(gè)方向(稱為初始定向),將原圖改為有向圖G',然后的任務(wù)就是改變G'中某些邊的方向(當(dāng)然是無向邊轉(zhuǎn)化來的,原混合圖中的有向邊不能動(dòng))使其滿足每個(gè)點(diǎn)的入度等于出度。
設(shè)D[i]為G'中(點(diǎn)i的出度 - 點(diǎn)i的入度)。可以發(fā)現(xiàn),在改變G'中邊的方向的過程中,任何點(diǎn)的D值的奇偶性都不會(huì)發(fā)生改變(設(shè)將邊<i, j>改為<j, i>,則i入度加1出度減1,j入度減1出度加1,兩者之差加2或減2,奇偶性不變)!而最終要求的是每個(gè)點(diǎn)的入度等于出度,即每個(gè)點(diǎn)的D值都為0,是偶數(shù),故可得:若初始定向得到的G'中任意一個(gè)點(diǎn)的D值是奇數(shù),那么原圖中一定不存在歐拉環(huán)!若初始D值都是偶數(shù),則將G'改裝成網(wǎng)絡(luò):設(shè)立源點(diǎn)S和匯點(diǎn)T,對(duì)于每個(gè)D[i]>0的點(diǎn)i,連邊<S, i>,容量為D[i]/2;對(duì)于每個(gè)D[j]<0的點(diǎn)j,連邊<j, T>,容量為-D[j]/2;G'中的每條邊在網(wǎng)絡(luò)中仍保留,容量為1(表示該邊最多只能被改變方向一次)。求這個(gè)網(wǎng)絡(luò)的最大流,若S引出的所有邊均滿流,則原混合圖是歐拉圖,將網(wǎng)絡(luò)中所有流量為1的中間邊(就是不與S或T關(guān)聯(lián)的邊)在G'中改變方向,形成的新圖G”一定是有向歐拉圖;若S引出的邊中有的沒有滿流,則原混合圖不是歐拉圖。為什么能這樣建圖?
考慮網(wǎng)絡(luò)中的一條增廣路徑S-->i-->...-->j-->T,將這條從i到j(luò)的路徑在G'中全部反向,則:i的入度加1出度減1,j的入度減1出度加1,路徑中其它點(diǎn)的入度出度均不變。而i是和S相連的,因此初始D[i]>0,即i的出度大于入度,故這樣反向之后D[i]減少2;同理,j是和T相連的,這樣反向之后D[j]增加2。因此,若最大流中邊<S, i>滿流(流量為初始D[i]/2),此時(shí)D[i]值就變成了0,也就是i的入度等于出度。因此只要使所有S引出的邊全部滿流,所有初始D值>0的點(diǎn)的D值將等于0,又因?yàn)閷⑦呑兿蚝笏悬c(diǎn)的D值之和不變,所有初始D值小于0的點(diǎn)的D值也將等于0,而初始D值等于0的D點(diǎn)既不與S相連也不與T相連,所以它們是網(wǎng)絡(luò)中的中間點(diǎn),而中間點(diǎn)的流入量等于流出量,故它們的入度和出度一直不變,即D值一直為0。因此,整個(gè)圖G'成為歐拉圖。(2)歐拉路徑的判定:
首先可以想到的是枚舉歐拉路徑的起點(diǎn)i和終點(diǎn)j,然后在圖中添加邊<j, i>,再求圖中是否有歐拉回路即可。但是,該算法的時(shí)間復(fù)雜度達(dá)到了O(M * 最大流的時(shí)間),需要優(yōu)化。
前面已經(jīng)說過,在將邊變向的過程中任何點(diǎn)的D值的奇偶性都不會(huì)改變,而一個(gè)有向圖有歐拉路徑的充要條件是基圖連通且有且只有一個(gè)點(diǎn)的入度比出度少1(作為歐拉路徑的起點(diǎn)),有且只有一個(gè)點(diǎn)的入度比出度多1(作為終點(diǎn)),其余點(diǎn)的入度等于出度。這就說明,先把圖中的無向邊隨便定向,然后求每個(gè)點(diǎn)的D值,若有且只有兩個(gè)點(diǎn)的初始D值為奇數(shù),其余的點(diǎn)初始D值都為偶數(shù),則有可能存在歐拉路徑(否則不可能存在)。進(jìn)一步,檢查這兩個(gè)初始D值為奇數(shù)的點(diǎn),設(shè)為點(diǎn)i和點(diǎn)j,若有D[i]>0且D[j]<0,則i作起點(diǎn)j作終點(diǎn)(否則若D[i]與D[j]同號(hào)則不存在歐拉路徑),連邊<j, i>,求是否存在歐拉環(huán)即可(將求出的歐拉環(huán)中刪去邊<j, i>即可)。這樣只需求一次最大流。 Code:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cmath>
#include<iostream>
using namespace std;
const int N=205,M=20005,INF=0x3f3f3f3f;
int t,S,T,n,m,cnt,tot;
int cur[N],Head[N],h[N],Q[N],d[N];
struct Noe{int to,Next,v;
}Edge[M];
void insert(int u,int v,int w){Edge[++cnt].to=v;Edge[cnt].Next=Head[u];Head[u]=cnt;Edge[cnt].v=w;Edge[++cnt].to=u;Edge[cnt].Next=Head[v];Head[v]=cnt;Edge[cnt].v=0;
}
bool bfs(){int head=0,tail=1;memset(h,-1,sizeof(h));Q[0]=S;h[S]=0;while(head!=tail){int now=Q[head++];for(int i=Head[now];i;i=Edge[i].Next){if(Edge[i].v&&h[Edge[i].to]==-1){h[Edge[i].to]=h[now]+1;Q[tail++]=Edge[i].to;}}}return h[T]!=-1;
}
int dfs(int x,int f){if(x==T){return f;}int w,used=0;for(int i=cur[x];i;i=Edge[i].Next){if(h[Edge[i].to]==h[x]+1){w=dfs(Edge[i].to,min(f-used,Edge[i].v));Edge[i].v-=w;Edge[i^1].v+=w;if(Edge[i].v){cur[x]=i;}used+=w;if(used==f){return f;}}}if(!used){h[x]=-1;}return used;
}
int dinic(){int tmp=0;while(bfs()){for(int i=S;i<=T;i++){cur[i]=Head[i];}tmp+=dfs(S,INF);}return tmp;
}
bool judge(){for(int i=1;i<=n;i++){if(d[i]%2!=0){return 0;}}return 1;
}
int main(){int u,v,opt;scanf("%d",&t);while(t--){memset(Head,0,sizeof(Head));memset(d,0,sizeof(d));cnt=1,tot=0;scanf("%d%d",&n,&m);T=n+1;for(int i=1;i<=m;i++){scanf("%d%d%d",&u,&v,&opt);d[u]++;d[v]--;if(opt==0){insert(u,v,1);}}for(int i=1;i<=n;i++){if(d[i]<0){insert(i,T,-d[i]/2);}if(d[i]>0){insert(0,i,d[i]/2);tot+=d[i]/2;}}if(!judge()){printf("impossible\n");continue;}if(tot!=dinic()){printf("impossible\n");}else{printf("possible\n");}}return 0;
}
轉(zhuǎn)載于:https://www.cnblogs.com/ukcxrtjr/p/11295264.html
總結(jié)
以上是生活随笔為你收集整理的混合图的欧拉路径和欧拉回路判断的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Quartz.Net - Lesson
- 下一篇: 软件开发