1. 程式人生 > >初學歐拉回路/路徑的判定 & 尤拉圖的有關問題

初學歐拉回路/路徑的判定 & 尤拉圖的有關問題

歐拉回路

簡介:

  • 歐拉回路:每條邊恰好只走一次,並能回到出發點的路徑.
  • 尤拉路徑:經過每一條邊一次,但是不要求回到出發點.
  • 尤拉圖:圖當且僅存在歐拉回路.
  • 半尤拉圖:圖當且僅存在尤拉路徑.

常規操作:

  • 關於尤拉圖的問題,一般是判迴路的存在性或生成一個(半)尤拉圖的代價或方案.
  • 判尤拉圖,即判存在迴路,這裡通過判點的度數來實現.
  • 生成尤拉圖的代價,類似於一筆畫,這時候就要通過一些結論再判定一下即可.
  • 求尤拉圖的方案,一般即為無向圖變有向圖,同時滿足尤拉圖.
  • 一般的,通過並查集來合併歐拉回路點集

歐拉回路的判定:

  1. 在無向圖中,每個點的度數都是偶數,則存在歐拉回路。
  2. 在有向圖中,每個點的入度
    等於出度,則存在歐拉回路。

尤拉路徑的判定:

  1. 在無向圖中,當且僅當所有點的度數為偶數或者除了兩個度數為奇數外其餘的全是偶數
  2. 在有向圖中,當且僅當該圖所有點的度數為0或者 一個點的度數為1,另一個度數為1,其他點的度數為0

有關判定迴路的例題:HDU 1116 Play on Words

Description:

判斷 n個單詞是 否可以相連成一條鏈,兩的件個單詞是 否可以相連成一條鏈,兩的件個單詞是 否可以相連成一條鏈,兩的件前一個單 詞的最後字母和詞。

Solution:

  • 通過每個單詞的首尾為邊,記錄點的入度與出度,
  • 通過並查集判點集個數,進而判定是否為尤拉圖。

Code:

#include<bits/stdc++.h>
using namespace std;
#define REP(i,f,t)for(int i=(f),i##_end_=(t);i<=i##_end_;i++)
#define SREP(i,f,t)for(int i=(f),i##_end_=(t);i<i##_end_;i++)
#define DREP(i,f,t)for(int i=(f),i##_end_=(t);i>=i##_end_;i--)
#define db double
#define LL long long 
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f #define Sz(a)sizeof(a) #define mcl(a,b)memset(a,b,Sz(a)) #define mcp(a,b)memcpy(a,b,Sz(b)) #define pb push_back #define fi first #define se second template<class T>inline bool chkmin(T&x,T y){return y<x?x=y,1:0;} template<class T>inline bool chkmax(T&x,T y){return x<y?x=y,1:0;} inline LL Max(LL x,LL y){return x>y?x:y;} inline LL Min(LL x,LL y){return x<y?x:y;} typedef pair<int,int>PII; #define N 30 int n; char s[1002]; int In[N],Out[N],fa[N]; int find(int x){return x==fa[x]?x:find(fa[x]);} void Clear(){ mcl(In,0); mcl(Out,0); SREP(i,1,N)fa[i]=i; } int main(){ int cas;scanf("%d",&cas); while(cas--){ Clear(); scanf("%d",&n); REP(i,1,n){ scanf("%s",s); int len=strlen(s); int x=s[0]-'a'+1; int y=s[len-1]-'a'+1; Out[x]++; In[y]++; x=find(x),y=find(y); if(x!=y)fa[y]=x; } bool f=1; int innum=0,outnum=0,root=0; SREP(i,1,N){ if(!In[i] && !Out[i])continue; if(fa[i]==i){ root++; if(root>1){f=0;break;} } if(In[i]!=Out[i]){ if(In[i]-Out[i]==1)innum++; else if(Out[i]-In[i]==1)outnum++; else {f=0;break;} } } if(f && ((!innum && !outnum) || (innum==1 && outnum==1)))puts("Ordering is possible."); else puts("The door cannot be opened."); } return 0; }

有關(半)尤拉圖的代價問題: HDU 3018 Ant Trip

Description:

給出一張無向圖,求最少幾筆能畫完這張圖。

首先,我們需要知道一些性質

  1. 孤立點,代價為0畫。
  2. (半)尤拉圖,代價為1畫。
  3. 非(半)尤拉圖,代為為奇數度的點數/2畫。

Prove:

  • 首先,(半)尤拉圖中點的度數都位偶數,那麼就會有出度等於入度,故為1畫;
  • 其次,非(半)尤拉圖中存在點的度數為奇數,
  • 對於每1畫,我們都會使一個連通量中的2個奇數度點為偶數,
  • 當最後一筆的時候我們必然消除所有的點的度數(包括剩下的兩個奇點,因為最後一筆就必然是尤拉路徑)。

Code:

#include<bits/stdc++.h>
using namespace std;
#define REP(i,f,t)for(int i=(f),i##_end_=(t);i<=i##_end_;i++)
#define SREP(i,f,t)for(int i=(f),i##_end_=(t);i<i##_end_;i++)
#define DREP(i,f,t)for(int i=(f),i##_end_=(t);i>=i##_end_;i--)
#define db double
#define LL long long 
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define Sz(a)sizeof(a)
#define mcl(a,b)memset(a,b,Sz(a))
#define mcp(a,b)memcpy(a,b,Sz(b))
#define pb push_back
#define fi first
#define se second
template<class T>inline bool chkmin(T&x,T y){return y<x?x=y,1:0;}
template<class T>inline bool chkmax(T&x,T y){return x<y?x=y,1:0;}
inline LL Max(LL x,LL y){return x>y?x:y;}
inline LL Min(LL x,LL y){return x<y?x:y;}
typedef pair<int,int>PII;

#define N 100002

/*
    此題我們可以知道一些性質:
    1.孤立點 -> 0 畫
    2.(半)尤拉圖 -> 1 畫
    3.非(半)尤拉圖 -> 奇數度的點個數/2 畫
*/

int n,m;
int fa[N];
int degree[N];
int sum[N],cnt[N];
// sum[i]表示該聯通量的點數 
// cnt[i]表示該聯通量的奇數度點數 

int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}

void Clear(){
    mcl(degree,0);
    mcl(sum,0);
    mcl(cnt,0); 
    REP(i,1,n)fa[i]=i;
}

int main(){
    while(~scanf("%d%d",&n,&m)){

        Clear();

        REP(i,1,m){
            int x,y;
            scanf("%d%d",&x,&y);
            degree[x]++,degree[y]++;
            x=find(x),y=find(y);
            if(x!=y)fa[x]=y;
        }

        REP(i,1,n){
            int root=find(i);
            sum[root]++;
            cnt[root]+=(degree[i]&1);
        }
        int ans=0;
        REP(i,1,n){
            if(sum[i]<2)continue;
            ans+=(!cnt[i])?1:(cnt[i]>>1);
        }
        printf("%d\n",ans);
    }
    return 0;
}

有關生成尤拉圖的方案問題:HDU 5348 MZL’s endless loop

Description:

給一個無向圖,讓你指定邊的方向,比如 a→b 為 1,a←b 為 0,在給所有邊指定方向後,對無向圖上的每個點,如果滿足|出度-入度|<2,那麼輸出任意一種方案。

Solution:

  • 因為我們要滿足條件,
  • 那麼就要儘可能有多的尤拉路徑,
  • 那麼我們就根據入度與出度的大小關係,
  • 進行dfs傳遞到該尤拉路徑中。

Code:

#include<bits/stdc++.h>
using namespace std;
#define REP(i,f,t)for(int i=(f),i##_end_=(t);i<=i##_end_;i++)
#define SREP(i,f,t)for(int i=(f),i##_end_=(t);i<i##_end_;i++)
#define DREP(i,f,t)for(int i=(f),i##_end_=(t);i>=i##_end_;i--)
#define db double
#define LL long long 
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define Sz(a)sizeof(a)
#define mcl(a,b)memset(a,b,Sz(a))
#define mcp(a,b)memcpy(a,b,Sz(b))
#define pb push_back
#define fi first
#define se second
template<class T>inline bool chkmin(T&x,T y){return y<x?x=y,1:0;}
template<class T>inline bool chkmax(T&x,T y){return x<y?x=y,1:0;}
inline LL Max(LL x,LL y){return x>y?x:y;}
inline LL Min(LL x,LL y){return x<y?x:y;}
typedef pair<int,int>PII;

#define N 100002
#define M 300002

int n,m;

int qwq,head[N];
struct edge{
    int to,next;
}E[M<<1];
void addedge(int x,int y){E[qwq]=(edge){y,head[x]};head[x]=qwq++;}

int degree[N],du[2][N];
bool vis[M<<1];
int ans[M];

void Clear(){
    mcl(degree,0);
    mcl(du,0);
    mcl(vis,0);
    qwq=0;
    mcl(head,-1);
    mcl(ans,-1);
}

void dfs(int x,int op){
    for(int &i=head[x];~i;i=E[i].next)if(!vis[i]){
        int y=E[i].to;
        if(y!=x && du[op][y]<du[op^1][y])continue;
        vis[i]=vis[i^1]=1;
        if(i&1)ans[i>>1]=op^1;
        else ans[i>>1]=op;
        du[op][x]++;
        du[op^1][y]++;
        dfs(y,op);
        break;
    }
}

int main(){
    int cas;cin>>cas;
    while(cas--){
        scanf("%d%d",&n,&m);

        Clear();

        SREP(i,0,m){
            int x,y;
            scanf("%d%d",&x,&y);
            degree[x]++,degree[y]++;
            addedge(x,y),addedge(y,x);
        }

        REP(i,1,n) while(du[0][i]+du[1][i]<degree[i]) dfs(i,(du[0][i]<=du[1][i])?0:1);

        SREP(i,0,m)printf("%d\n",ans[i]);
    }
    return 0;
}

Summary:

  • 雖說尤拉圖是一個比較冷門的考點,但是難起來還是非常玄學的…蒟蒻太菜了
  • 但是為了防冷門,這裡還是初學了一些皮毛除了判定,最多再求個方案或算個代價真的沒了呀...

相關推薦

初學/路徑判定 & 有關問題

歐拉回路 簡介: 歐拉回路:每條邊恰好只走一次,並能回到出發點的路徑. 尤拉路徑:經過每一條邊一次,但是不要求回到出發點. 尤拉圖:圖當且僅存在歐拉回路. 半尤拉圖:圖當且僅存在尤拉路徑. 常規操作: 關於尤拉圖的問題,一般是判迴路的存在性或生

UOJ 117 (套圈法+路徑輸出+騷操作)

height int ima 標記 圖片 style 技術分享 () targe 題目鏈接:http://uoj.ac/problem/117 題目大意: 解題思路:先判斷度數:      若G為有向圖,歐拉回路的點的出度等於入度。      若G為無向圖,歐拉

hud 1878 判定

Problem Description 歐拉回路是指不令筆離開紙面,可畫過圖中每條邊僅一次,且可以回到起點的一條迴路。現給定一個圖,問是否存在歐拉回路? Input 測試輸入包含若干測試用例。每個測試用例的第1行給出兩個正整數,分別是節點數N ( 1 <

codeforces 723e One-Way Reform () || 路徑輸出模板

There are n cities and m two-way roads in Berland, each road connects two cities. It is known that there is no more than one road con

無向道路()的判定路徑打印

clu clas 檢查 names 連通圖 思路 return space 計算 歐拉道路描述的是無向圖的一個頂點出發的一條道路能夠經過每條邊恰好一次 歐拉回路指的是任意點出發都滿足上述性質 如果一個圖是歐拉道路或者歐拉回路,必須滿足兩個條件 第一個條件,這個圖是連通圖 第

-路徑

有一條名為Pregel的河流經過Konigsberg城。城中有7座橋。把河中的兩個島與河岸連線起來。當地居民熱衷於一個難題:是否存在於一條路線,可以不重複地走遍7座橋。這就是著名的七橋問題。它由大數學家尤拉首先提出,並給出了完美的解答。 尤拉首先把圖中的七橋問題用圖論的語言

路徑詳解

歐拉回路定義: 歐拉回路:每條邊恰好只走一次,並能回到出發點的路徑 尤拉路徑:經過每一條邊一次,但是不要求回到起始點 首先看歐拉回路存在性的判定(這裡先不說混合圖): 一、無向圖 每個頂點的度數都是偶數,則存在歐拉回路。 二、有向圖(所有邊都是單向的) 每個節頂

路徑,並查集

1.1 定義 對於圖G,若存在一條路徑,經過G中每條邊有且僅有一次,稱這條路為尤拉路徑;如果存在一條迴路經過G每條邊有且僅有一次,稱這條迴路為歐拉回路。具有歐拉回路的圖成為尤拉圖。 1.2 判斷尤拉路徑是否存在的方法 有向圖:圖連通,且只有一個頂點出度大入度1,有一

路徑某些問題集合

後續會給出一些程式碼 問題一: n個點,m個雙向邊,無重邊,可能有自環,一條航線需要滿足以下要求:從任意一個點出發,在任意一個點結束,經過m-2條邊恰好2次,經過2條邊恰好1次。求有多少本質不同的航線,兩航線本質不同當且僅當存在1條邊,在兩航線

hdu5348(+路徑)

題意:n個點m條邊的無向圖,問是否滿足將所有邊變為有向後,每個點入度和出度的點不超過1 程式碼:#include <stdio.h> #include <stdlib.h> #include <string.h> #include &l

杭電ACM1116——Play on Words~~路徑

這一題,相比之前做的題目,增加了尤拉路徑的求解。而且這一題是有向圖。題目大概的意思就是成語接龍,能接起來就算可以開啟門,因此要考慮兩種,一種是迴路,另外一種是一條路徑。 第一次WR就是因為沒有考慮迴路這一個因素。 有向圖中,歐拉回路與尤拉路徑的求解方法: 1.歐拉回路: 首

路徑

定義 給一個連通圖,求一條每條邊恰好走一次的路徑,就叫尤拉路徑,如果要求回到原點,就叫歐拉回路。(也叫一筆畫問題) 推論 無向圖 把度數為偶數的點叫偶點,度數為奇數的點叫奇點。 如果一個圖存在尤拉路徑,則奇點的個數一定為0個或2個。 白話證

路徑

歐拉回路是數學家尤拉在研究著名的德國哥尼斯堡(Koenigsberg)七橋問題時發現的 尤拉由此提出 了著名的尤拉定理。 1)尤拉路:通過圖中所有邊的簡單路。 2)歐拉回路:閉合的尤拉路。 3)尤拉圖:包含歐拉回路的圖。  簡單地說:在圖上的一條經過所有的邊一次且只有一次的路

[模板][持續更新]路徑淺析

bits solution 算法 -1 要求 logs 鏈式前向星 namespace src Luogu P2731 騎馬修柵欄 Riding the Fences 題目背景 Farmer John每年有很多柵欄要修理。他總是騎著馬穿過每一個柵欄並修復它破損的地方。 題目

51nod 1967 路徑定向(不錯的

cnblogs 偶數 ret mes stack ostream lin .html pre http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1967 題意: 思路: 出度=入度,這

51nod1967 路徑定向(+結論題)

void ++i col () view const stdio.h turn char   看到入度等於出度想到歐拉回路。   我們把邊都變成無向邊,有一個結論是偶數度的點都可以變成出入度相等的點,而奇數點的不行,感性理解分類討論一下就知道是對的。   還有一個更好理

新知識添加·+路徑

應該 路徑 求解 兩種方法 遍歷 fleury 歐拉路 必要條件 bsp §概念 歐拉通路: 通過圖中每條邊且只通過一次,並且經過每一頂點的通路; 歐拉回路: 通過圖中每條邊且只通過一次,並且經過每一頂點的回路; 歐拉環:圖中經過每條邊一次且僅一次的環; 歐拉路徑:圖中經過

路徑

證明 dfs HR 無向圖 tro post 重要 strong line 歐拉回路與歐拉路徑 如果圖G中的一個路徑包括每個邊恰好一次,則該路徑稱為歐拉路徑(歐拉通路)。 如果一個回路是歐拉路徑,則稱為歐拉回路(Euler circuit)。 說的直白點,歐拉回路就是從一個

&& 路徑

main aps lin 技術 c++ edge AD rac ans 歐拉路徑(瞎)定義 : 如果有一條路徑使得能夠走完所有的邊且每一條邊經過有且只有一次,這樣的路徑叫做歐拉路徑 歐拉回路定義 : 如果有從起點出發最後回到起點的一條路徑使得能夠走完所有的邊且每條邊經過有且

路徑POJ 2230

possible 圖片 pac ans close rails AI show pair Watchcow Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 8841