實驗六歐拉圖判定和應用
【實驗目的】掌握判斷歐拉圖的方法。
【實驗內容】編程隨機生成n個結點的無向圖(有向圖)並能進行(半)歐拉圖的判定,若是則給出所有歐拉路.
【要求】對給定n個結點,隨機生成鄰接矩陣以確定某無向簡單圖(有向圖)並進行歐拉圖和半歐拉圖的判定,若符合則給出至少一條歐拉回路或歐拉路。
【實驗原理和方法】
是根據隨機生成的圖求歐拉(回)路,先要隨機生成一個鄰接矩陣,然后判定是否是歐拉回路只要根據奇數度結點的個數。再用一個遞歸函數找出歐拉路。
(1)用關系矩陣R=表示圖。
(2)對無向圖而言,若所有結點的度都是偶數,則該圖為歐拉圖。
C語言算法:
flag=1;
for(i=1;i<=n && flag;i++)
{
sum=0;
for(j=1;j<=n;j++)
if(r[i][j]) sum++;
if(sum%2==0) flag=0;
}
如果 flag 該無向圖是歐拉圖
(3)對有向圖而言,若所有結點的入度等於出度,則該圖為歐拉圖。
C語言算法:
flag=1;
for(i=1;i<=n && flag;i++)
{
sum1=0;
sum2=0;
for(j=1;j<=n;j++)
if(r[i][j]) sum1++;
for(j=1;j<=n;j++)
if(r[j][i]) sum2++;
if(sum1%2==0 || sum2%2==0) flag=0;
}
如果 flag 該有向圖是歐拉圖
(4)求出歐拉路的方法:歐拉路經過每條邊一次且僅一次。可用回溯的方法求得所有歐拉路。
C語言算法:
intcount=0,cur=0,r[N][N]; // r[N][N]為圖的鄰接矩陣,cur為當前結點編號,count為歐拉路的數量。
int sequence[M];// sequence保留訪問點的序列,M為圖的邊數
輸入圖信息;
void try1(int k) //k表示邊的序號
{
int i,pre=cur; //j保留前一個點的位置,pre為前一結點的編號
for (i=0;i<N;i++)
if (r[cur][i]) //當前第cur點到第i點連通
{
//刪除當前點與第i點的邊,記下第k次到達點i,把第i個點設為當前點
r[cur][i]=0;cur=sequence[k]=i;
if (k<M) try1(k+1); //試下一個點
else prt1();//經過了所有邊,打印一個解
//上面條件不滿足,說明當前點的出度為0,回溯,試下一位置
r[pre][i]=1;cur=pre;
}
}
附上代碼:
有向圖:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <time.h> int n,a[100][100],m=0,visit[100]; int cur=0,s[100],vis[100][100]; void try1(int k)//取歐拉路 { int i; if(cur==m+1) { for(i=0;i<cur;i++) { if(i==0) printf("%d",s[i]+1); else printf("->%d",s[i]+1); } printf("\n"); } else { for(i=0;i<n;i++) { if(a[k][i]&&!vis[k][i]) { vis[k][i]=1; vis[i][k]=1; s[cur++]=i; try1(i); cur--; vis[k][i]=0; vis[i][k]=0; } } } } void dfs(int k) { int i; visit[k]=1; for(i=0;i<n;i++) { if(a[k][i]&&!visit[i]) { dfs(i); } } } int fun()//判斷連通性 { int i; dfs(0); for(i=0;i<n;i++) { if(!visit[i]) return 0; } return 1; } int main(void) { int i,j; memset(vis,0,sizeof(vis)); memset(visit,0,sizeof(visit)); srand(time(NULL)); printf("請輸入節點個數n:"); scanf("%d",&n); for(i=0;i<n;i++) { for(j=0;j<n;j++) { if(i==j) a[i][j]=0; else if(i>j) a[i][j]=a[j][i]; else a[i][j]=rand()%2; m+=a[i][j]; } } m/=2; printf("鄰接矩陣為:\n "); for(i=0;i<n;i++) { printf(" %d",i+1); } printf("\n"); for(i=0;i<n;i++) { printf("%d",i+1); for(j=0;j<n;j++) printf(" %d",a[i][j]); printf("\n"); } if(fun()==0) { printf("該圖不是連通圖!\n"); return 0; } printf("該圖是連通圖!\n"); int odd=0; for(i=0;i<n;i++) { int sum=0; for(j=0;j<n;j++) { if(a[i][j]) sum++; } if(sum%2) odd++; } if(odd==0) { printf("該圖沒有奇數度節點,具有歐拉回路,是歐拉圖。\n"); printf("所有的歐拉路為:\n"); for(i=0;i<n;i++) { s[cur++]=i; try1(i); cur--; } } else if(odd==2) { printf("該圖有兩個奇數度節點,具有歐拉路,是半歐拉圖。\n"); printf("所有的歐拉路為:\n"); for(i=0;i<n;i++) { int sum=0; for(j=0;j<n;j++) sum+=a[i][j]; if(sum%2)//起點或中點 { s[cur++]=i; try1(i); cur--; } } } else { printf("不是歐拉圖,也不是半歐拉圖\n"); } return 0; }
無向圖:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <time.h> int n,a[100][100],m=0,visit[100]; int cur=0,s[100],vis[100][100]; void try1(int k)//取歐拉路 { int i; if(cur==m+1) { for(i=0;i<cur;i++) { if(i==0) printf("%d",s[i]+1); else printf("->%d",s[i]+1); } printf("\n"); } else { for(i=0;i<n;i++) { if(a[k][i]&&!vis[k][i]) { vis[k][i]=1; s[cur++]=i; try1(i); cur--; vis[k][i]=0; } } } } void dfs(int k) { int i; visit[k]=1; for(i=0;i<n;i++) { if(a[k][i]&&!visit[i]) { dfs(i); } } } int fun()//判斷連通性 { int i,j; for(i=0;i<n;i++) { memset(visit,0,sizeof(visit)); dfs(i); for(j=0;j<n;j++) { if(!visit[j]) break; } if(j==n) return 1; } return 0; } int main(void) { int i,j; memset(vis,0,sizeof(vis)); srand(time(NULL)); printf("請輸入節點個數n:"); scanf("%d",&n); for(i=0;i<n;i++) { for(j=0;j<n;j++) { a[i][j]=rand()%2; m+=a[i][j]; } } printf("鄰接矩陣為:\n "); for(i=0;i<n;i++) { printf(" %d",i+1); } printf("\n"); for(i=0;i<n;i++) { printf("%d",i+1); for(j=0;j<n;j++) printf(" %d",a[i][j]); printf("\n"); } if(fun()==0) { printf("該圖不是連通圖!\n"); return 0; } printf("該圖是連通圖!\n"); int odd=0,begin=-1,end=-1; for(i=0;i<n;i++) { int sum1=0,sum2=0; for(j=0;j<n;j++) { sum1+=a[i][j]; sum2+=a[j][i]; } if(sum1!=sum2) { odd++; if(sum1-sum2==1) begin=i; if(sum2-sum1==1) end=i; } } if(odd==0) { printf("該圖所有點出度等於入度,具有歐拉回路,是歐拉圖。\n"); printf("所有的歐拉路為:\n"); for(i=0;i<n;i++) { s[cur++]=i; try1(i); cur--; } } else if(odd==2&&begin!=-1&&end!=-1) { printf("該圖有兩個奇數度節點,具有歐拉路,是半歐拉圖。\n"); printf("所有的歐拉路為:\n"); s[cur++]=begin; try1(begin); } else { printf("不是歐拉圖,也不是半歐拉圖\n"); } return 0; }
過一學期了第一次寫離散作業