1. 程式人生 > >1126 Eulerian Path(25 分)【並查集/dfs】

1126 Eulerian Path(25 分)【並查集/dfs】

題意:如果一個連通圖的所有結點的度都是偶數,那麼它就是Eulerian,如果除了兩個結點的度是奇數其他都是偶數,那麼它就是Semi-Eulerian,否則就是Non-Eulerian

歐拉回路:圖G的一個迴路,如果恰通過圖G的每一條邊,則該回路稱為歐拉回路,具有歐拉回路的圖稱為尤拉圖。

尤拉圖:就是從圖上的一點出發,經過所有邊且只能經過一次,最終回到起點的路徑。

尤拉通路:即可以不回到起點,但是必須經過每一條邊,且只能一次。也叫"一筆畫"問題。

判定條件(充要):

歐拉回路:1:  圖G是連通的,不能有孤立點存在。2:  對於無向圖來說度數為奇數的點個數為0;對於有向圖來說每個點的入度必須等於出度。

尤拉通路:1:  圖G是連通的,無孤立點存在。2:  對於無向圖來說,度數為奇數的的點可以有2個或者0個,並且這兩個奇點其中一個為起點另外一個為終點。對於有向圖來說,可以存在兩個點,其入度不等於出度,其中一個入度比出度大1,為路徑的起點;另外一個出度比入度大1,為路徑的終點。)

先通過並查集或dfs判斷是否為連通圖,然後判斷結點度數:

並查集:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x7FFFFF

int n,m;
vector<int> g[501];
int fa[501];

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

void Union(int x,int y)
{
    int xc=Find(x);
    int yc=Find(y);
    if(xc!=yc)
        fa[xc]=yc;
}


int main()
{
    while(cin>>n>>m)
    {
        int u,v; 
        for(int i=1;i<=n;i++)  //不要忘記初始化
            fa[i]=i;
        while(m--)
        {
            cin>>u>>v;
            g[u].push_back(v);
            g[v].push_back(u);
            Union(u,v);
        }
        int cnt=0;
        for(int i=1; i<=n; i++)
        {
            if(fa[i]==i)
                cnt++;
        }
        int odd=0;
        int f=1;
        for(int i = 1; i <= n ; i++)
        {
            int len = g[i].size();
            if(len % 2 ==1)
                odd++;
            if(f){
                cout<<len;
                f=0;
            }
            else
                cout<<" "<<len;
        }
        cout<<endl;
        if(odd==0&&cnt==1)
            cout<<"Eulerian"<<endl;

        else if(odd==2&&cnt==1)
            cout<<"Semi-Eulerian"<<endl;

        else
            cout<<"Non-Eulerian"<<endl;
    }

    return 0;
}

dfs:

int cnt = 0;
int vis[501];
void dfs(int index) 
{
    vis[index] = 1;
    cnt++;
    for (int i = 0; i <g[index].size(); i++)
        if (vis[g[index][i]] == 0)
            dfs(g[index][i]);
}

//在主函式中判斷:
    cnt==n