歐拉回路
定義:
- 給定一張圖,如何求出一條經過每條邊恰好一次的迴路。(行遍所有邊)
- 必要條件:
- 有向圖
1.給定的圖是一個強連通分量(基圖是連通)。
基圖就是把有向邊變爲無向邊。
2.每個點的入度等於出度(進來了一定要出去)。
3.不難發現這兩個條件其實也是充分的。
- 無向圖
1.每個點的度數都是偶數(even)
2.圖是連通的
圈套圈算法:
文字描述:
- 任選一個起點,從起點開始,每條邊只能被走一遍,當沒有邊可以走的時候把壓入答案隊列中。
- 最後的答案就是反着的歐拉回路。
解釋:
,1無路可走,把1壓入答案隊列。
,4無路可走,把4壓入答案隊列。
依次求得:1 4 6 5 4 3 2 1
所以1 2 3 4 5 6 4 1位一條歐拉回路。
- 原理:
理想狀態下就是一個環沒有分支,當存在分支又是連通分量(前提是歐拉圖),那麼就可以跑完這個環再去遍歷下一個環,依次回溯。(符合算法) - 複雜度:
代碼實現:
無向圖:
/*
無向圖的歐拉回路
鄰接矩陣存圖
*/
#include<cstdio>
#include<cstring>
const int N=1e3+10;
int ans[N];//存放點的順序
int book[N];//表示每個點的度數
int map[N][N];
int top,n,m;
void dfs(int x) {
for(int i=1; i<=n; i++) {
if(map[x][i]) {
map[x][i]--;
map[i][x]--;
dfs(i);
}
}
ans[top++]=x;//放入隊列中
}
void fleury(int x) {
top=0;
dfs(x);
}
void Print_road() { //輸出路徑
for(int i=top-1; i>=0; i--) {
printf("%d",ans[i]);
if(i) {
printf("-->");
}
}
puts("");
}
int main() {
int x;
while(~scanf("%d %d",&n,&m)) { //共有n個點,m個邊 //歐拉回路所有邊只走一次
memset(book,0,sizeof(book));
memset(map,0,sizeof(map));
for(int i=0; i<m; i++) {
int u,v;
scanf("%d %d",&u,&v);
book[u]++;
book[v]++;
map[u][v]=map[v][u]=1;
}//構建數組鏈表
x=1;
int cnt=0;
for(int i=1; i<=n; i++) {
if(book[i]&1) {
cnt++;
x=i;
}
}
if(!cnt||cnt==2) { //找出x
fleury(x);
Print_road();
} else {
printf("不存在歐拉回路\n");
continue;
}
}
}
有向圖:
/*
fleury 有向邊
用了鄰接表實現
*/
#include<cstdio>
#include<cstring>
const int N=1e3+10;
struct Node {
int v;
int next,index,flag;
} node[N];
int head[N];//存放每個u節點的第一個指向
int ans[N];//存放點的順序
int rbook[N],cbook[N];//表示每個點的度數
int top;
void dfs(int x) {
int to;
to=head[x];
while(to!=-1) {
if(node[to].flag) {
node[to].flag=0;
dfs(node[to].v);
}
to=node[to].next;
}
ans[top++]=x;
}
void fleury(int x) {
top=0;
dfs(x);
}
void Print_road() { //輸出路徑
for(int i=top-1; i>=0; i--) {
printf("%d",ans[i]);
if(i)
printf("-->");
}
puts("");
}
int main() {
int n,m,x;
while(~scanf("%d %d",&n,&m)) { //共有n個點,m個邊 //歐拉回路所有邊只走一次
memset(rbook,0,sizeof(rbook));
memset(cbook,0,sizeof(cbook));
memset(head,-1,sizeof(head));
for(int i=0; i<m; i++) {
int u,v;
scanf("%d %d",&u,&v);
cbook[u]++;
rbook[v]++;
node[i].v=v;
node[i].flag=1;
node[i].index=i;
node[i].next=head[u];
head[u]=i;
}//構建數組鏈表
x=1;
int cnt=0;
for(int i=1; i<=n; i++) {
if(rbook[i]!=cbook[i]) { //計算出度不等於入讀的個數
cnt++;
if(cbook[i]>rbook[i])//因爲總的出度與總的入度個數是相同的,所有必有一大一小
x=i;
}
}
if(!cnt||cnt==2) { //找出x
fleury(x);
Print_road();
} else {
printf("不存在歐拉回路\n");
continue;
}
}
return 0;
}
歐拉路徑
定義:
經過所有邊。相當於在歐拉回路里面去掉一條邊。
- 必要條件:
1.只有兩個度數爲奇數的點。
2.連通。