1. 程式人生 > >有向圖的歐拉回路及尤拉道路

有向圖的歐拉回路及尤拉道路

 歐拉回路

//有向圖

//歐拉回路:1.圖連通2.每個點的入度等於出度

//尤拉道路:1.圖連通2.每個點的入度等於出度或有兩個點入度不等於出度,且一個點出度比入度大一(起點),另一個點入度比出度小一(終點)如下圖只能從中間一點開始到中間另一點結束,並且起點出度比入度大一


//程式本身並不複雜,無非是將無向圖中對於度數的判斷奇偶改為判斷入度和出度是否相等
//儲存路徑時需要注意一點,ans陣列是儲存的兩點,而不是一點是否被訪問過(這與圖的遍歷不同,我一開始就錯這),因為歐拉回路是可能重複經過某一點的
#include <cstdio>
#include <iostream>
#include <queue>
using namespace std;
 int n;
 int a[101][101];
 int indegree[101];
 int outdegree[101];
 int bfs();
 int ans[101][101];
 int compare();
 void print(int i);
 int main()
 {

     int m,i,j,c,d;
     scanf("%d%d",&n,&m);
     for (i=1;i<=m;i++)
     {

         scanf("%d%d",&c,&d);
         a[c][d]=1;
         outdegree[c]++;//c的出度加一
         indegree[d]++;//d的入度加一
     }
     if (!bfs())//如果圖本身不連通
        printf("No\n");
        else

         if (compare())//如果入度等於出度
         {

            printf("Yes\n");
            printf("路徑為:\n");
            print(1);
         }
         else
        printf("No\n");
     return 0;
 }
 int bfs()
 {
     queue<int>q;
     int i;
     int vis[101],temp;//標記是否訪問過
     for (i=1;i<=n;i++)
        vis[i]=0;
     q.push(1);
     vis[1]=1;
     while(!q.empty())
     {

         temp=q.front();
         q.pop();
         for (i=1;i<=n;i++)
          if ((a[temp][i])&&(!vis[i]))
         {

             vis[i]=1;
             q.push(i);
         }
     }
     for (i=1;i<=n;i++)
        if (!vis[i])
        {
           printf("%d\n",i);
           return 0;
        }
         return 1;
}
int compare()
{
     int i;
    for (i=1;i<=n;i++)
        if (indegree[i]!=outdegree[i])
        return 0;
        return 1;
}
void print(int i)
{
    int v;
    for (v=1;v<=n;v++)
    if ((a[i][v])&&(!ans[i][v]))
    {
        ans[i][v]=1;
        printf("%d->%d\n",i,v);
        print(v);   //遞迴搜尋路徑

    }

}



   尤拉道路

//有向圖的尤拉道路的查詢即路徑列印方式與尤拉通路差不多,關鍵在於包含歐拉回路的情況下再考慮入度和出度相差1的情況
//有向圖的尤拉道路起點必須是出度比入度大一的那個點,所以要先掃描一遍找出那兩個點,如果都相等,那就參照歐拉回路的方式做,否則從該點開始路徑遞迴

#include <cstdio>
#include <iostream>
#include <queue>
#include <cmath>
using namespace std;
 int n;
 int a[101][101];
 int indegree[101];
 int outdegree[101];
 int bfs();
 int x[3];
 int ans[101][101];
 int compare();
 void print(int i);
 int main()
 {

     int m,i,j,c,d;
     scanf("%d%d",&n,&m);
     x[1]=0;
     for (i=1;i<=m;i++)
     {

         scanf("%d%d",&c,&d);
         a[c][d]=1;
         outdegree[c]++;//c的出度加一
         indegree[d]++;//d的入度加一
     }
     if (!bfs())//如果圖本身不連通
        printf("No\n");
        else
       if (compare())//如果入度等於出度
         {

            printf("Yes\n");
            printf("路徑為:\n");
            if (!x[1])//如果是歐拉回路,那麼哪一點開始都無所謂
                print(1);
            else
            if (outdegree[x[1]]>outdegree[x[2]])//如果a[1]的出度大,那他就是起點
            print(x[1]);
            else
                print(x[2]);
         }
         else
        printf("No\n");
     return 0;
 }
 int bfs()
 {
     queue<int>q;
     int i;
     int vis[101],temp;//標記是否訪問過
     for (i=1;i<=n;i++)
        vis[i]=0;
     q.push(1);
     vis[1]=1;
     while(!q.empty())
     {

         temp=q.front();
         q.pop();
         for (i=1;i<=n;i++)
            if ((a[temp][i])&&(!vis[i]))
         {

             vis[i]=1;
             q.push(i);
         }
     }
     for (i=1;i<=n;i++)
        if (!vis[i])
        {
           printf("%d\n",i);
           return 0;
        }
         return 1;


}
int compare()
{
    int i,ok;
    ok=0;
    for (i=1;i<=n;i++)
        if (indegree[i]!=outdegree[i])
        {
            ok++;
            if (ok>2)return 0;//如果入度出度不相等的節點數大於2,那肯定不是尤拉道路
            else
            x[ok]=i;

        }
        if (!ok)//如果入度都等於出度,那麼是歐拉回路,自然是尤拉通路
        return 1;
        if (fabs(indegree[x[1]]-indegree[x[2]])!=1)//如果入度相差不是1,那也不是歐拉回路
           return 0;
}
void print(int i)
{
    int v;
    for (v=1;v<=n;v++)
    if ((a[i][v])&&(!ans[i][v]))
    {
        ans[i][v]=1;
        printf("%d->%d\n",i,v);
        print(v);   //遞迴搜尋路徑

    }

}