歐拉路和歐拉回路


一、基本概念:

歐拉路:歐拉路是指從圖中任意一個點開始到圖中任意一個點結束的路徑,並且圖中每條邊通過的且只通過一次

歐拉回路:歐拉回路是指起點和終點相同的歐拉路。


二、存在歐拉路的條件:

1.無向連通圖存在歐拉路的條件:

所有點度都是偶數,或者恰好有兩個點度是奇數,則有歐拉路。若有奇數點度,則奇數點度點一定是歐拉路的起點和終點,否則可取任意一點作為起點。

2.有向連通圖存在歐拉路的條件:

  • 每個點的入度等於出度,則存在歐拉回路(任意一點有度的點都可以作為起點)
  • 除兩點外,所有入度等於出度。這兩點中一點的出度比入度大,另一點的出度比入度小,則存在歐拉路。取出度大者為起點,入度大者為終點。

三、算法實現:主要分為dfs和並查集兩種方法,具體使用請看下面的題目


四、題目:

1.一筆畫問題(NYOJ42)

描述

zyc從小就比較喜歡玩一些小游戲,其中就包括畫一筆畫,他想請你幫他寫一個程序,判斷一個圖是否能夠用一筆畫下來。

規定,所有的邊都只能畫一次,不能重復畫。

輸入

第一行只有一個正整數N(N<=10)表示測試數據的組數。 每組測試數據的第一行有兩個正整數P,Q(P<=1000,Q<=2000),分別表示這個畫中有多少個頂點和多少條連線。(點的編號從1到P) 隨后的Q行,每行有兩個正整數A,B(0 < A,B < P),表示編號為A和B的兩點之間有連線。

輸出

如果存在符合條件的連線,則輸出"Yes", 如果不存在符合條件的連線,輸出"No"。

樣例輸入

2
4 3
1 2
1 3
1 4
4 5
1 2
2 3
1 3
1 4
3 4

樣例輸出

No

Yes

分析:這題是一題很經典的判斷是否存在歐拉路的題目,我用了dfs和並查集兩種方法寫了這題,注意dfs要有適當的剪枝。下面請看兩種ac代碼:

dfs version:

 
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;

const int maxn=1002;
vector<int> graph[maxn];
int n,m,cnt,in;
bool visited[maxn];

void dfs(int v)
{
    for(int i=0;i<graph[v].size();i++)
    {
        int e=graph[v][i];
        if(!visited[e])
        {
            cnt++;
            if(graph[e].size()%2)
                in++;
            visited[e]=true;
            dfs(e);
        }
    }
}

int main()
{
    int t;
    cin>>t;
    while (t--) {
        cin>>n>>m;

        for(int i=0;i<=n;i++)
            graph[i].clear();

        for(int i=0;i<m;i++)
        {
            int x,y;
            cin>>x>>y;
            graph[x].push_back(y);
            graph[y].push_back(x);
        }

        cnt=0;
        in=0;
        memset(visited,false,sizeof(visited));
        dfs(1);

        if((m==0&&n==1)||(cnt==n&&(in==0||in==2)))
            cout<<"Yes"<<endl;
        else
            cout<<"No"<<endl;
    }
}
        
View Code

 

並查集方法

 
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int maxn=1005;
int degree[maxn];
int fa[maxn];

void init()
{
    for(int i=0;i<maxn;i++)
        fa[i]=i;
}

int find(int x)
{
    if(x==fa[x])
        return x;
    else
    {
        return fa[x]=find(fa[x]);
    }
}

void unite(int x,int y)
{
    int rx=find(x);
    int ry=find(y);
    fa[ry]=rx;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(degree,0,sizeof(degree));
        init();
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            degree[x]++;
            degree[y]++;
            unite(x,y);
        }

        int root=find(1),cnt=0,d=0;
        for(int i=1;i<=n;i++)
        {
            if(find(i)!=root)
                cnt++;
            if(degree[i]%2)
                d++;
        }

        if(!cnt&&(d==0||d==2))
            printf("Yes\n");
        else
            printf("No\n");
    }
}
        
View Code

 


2.Ant trip (HDU 3018)

Ant Country consist of N towns.There are M roads connecting the towns.

Ant Tony,together with his friends,wants to go through every part of the country.

They intend to visit every road , and every road must be visited for exact one time.However,it may be a mission impossible for only one group of people.So they are trying to divide all the people into several groups,and each may start at different town.Now tony wants to know what is the least groups of ants that needs to form to achieve their goal.

Input

Input contains multiple cases.Test cases are separated by several blank lines. Each test case starts with two integer N(1<=N<=100000),M(0<=M<=200000),indicating that there are N towns and M roads in Ant Country.Followed by M lines,each line contains two integers a,b,(1<=a,b<=N) indicating that there is a road connecting town a and town b.No two roads will be the same,and there is no road connecting the same town.

Output

For each test case ,output the least groups that needs to form to achieve their goal.

Sample Input

3 3
1 2
2 3
1 3

Sample Output

1

2

Hint

New ~~~ Notice: if there are no road connecting one town ,tony may forget about the town. In sample 1,tony and his friends just form one group,they can start at either town 1,2,or 3. In sample 2,tony and his friends must form two group.

分析:

這題和上面的那一題稍微有點不同,這題求的是最少筆數。顯然,這是屬於歐拉回路的變形,首先要判斷一共有多少個連通塊,然后對每個連通塊通過入度和出度判斷筆數即可,即對於每個連通塊的筆數:ceil(奇數度的點的個數/2.0),如果奇數度的點的個數為0,則筆數為1.

Accepted code:

 

#include<cstdio>
#include<cstring>
#include<map>
#include<cmath>
using namespace std;

const int maxn=100005;
int fa[maxn];
int degree[maxn];
int n,m;

void init()
{
    for(int i=0;i<=n;i++)
        fa[i]=i;
    memset(degree,0,sizeof(degree));
}

int FindRoot(int x)
{
    if(x==fa[x])
        return x;
    else
        return fa[x]=FindRoot(fa[x]);
}

void unite(int x,int y)
{
    int rx=FindRoot(x);
    int ry=FindRoot(y);
    if(rx!=ry)
    {
        fa[rx]=ry;
    }
}

int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        init();
        for(int i=1;i<=m;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            degree[x]++;
            degree[y]++;
            unite(x,y);
        }
        
        map<int,int> cnt;
        cnt.clear();
        
        for(int i=1;i<=n;i++)
        {
            int ri=FindRoot(i);
            if(!cnt.count(ri)&&degree[ri]) cnt[ri]=0;
            if(degree[i]%2)
                cnt[ri]++;
        }
        
        int ans=0;
        for(map<int,int>::iterator it=cnt.begin();it!=cnt.end();it++)
        {
            if(it->second==0)
            {
                ans+=1;
            }
            else
                ans+=ceil(it->second/2.0);
            
        }
        
        printf("%d\n",ans);
    }
}
View Code

 

由於時間原因,還有的題目分析我就不放上來了,只給出題目給大家練習吧。

HDU 1878 HDU 1116


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM