本題考查點:
- 歐拉回路 [TOC]
哥尼斯堡是位於普累格河上的一座城市,它包含兩個島嶼及連接它們的七座橋,如下圖所示。 可否走過這樣的七座橋,而且每橋只走過一次?瑞士數學家歐拉(Leonhard Euler,1707—1783)最終解決了這個問題,並由此創立了拓撲學。 這個問題如今可以描述爲判斷歐拉回路是否存在的問題。歐拉回路是指不令筆離開紙面,可畫過圖中每條邊僅一次,且可以回到起點的一條迴路。現給定一個無向圖,問是否存在歐拉回路? 輸入格式: 輸入第一行給出兩個正整數,分別是節點數N (1≤N≤1000)和邊數M;隨後的M行對應M條邊,每行給出一對正整數,分別是該條邊直接連通的兩個節點的編號(節點從1到N編號)。 輸出格式: 若歐拉回路存在則輸出1,否則輸出0。
在做本題之前,我們先來複習一下歐拉圖,歐拉回路,歐拉通路的一些性質:
歐拉圖、歐拉通路與歐拉回路
歐拉圖的定義:
- 設 G 是無孤立結點的圖,若存在一條通路 (迴路),經過圖中每邊一次且僅一次,則稱 此通路 (迴路) 爲該圖的一條歐拉通路 (迴路)。具有歐拉回路的圖稱爲歐拉圖(Eulerian graph)
無向歐拉圖判定定理
- 歐拉回路:無向圖 G =< V, E > 具有一條歐拉回路,當且僅當 G 是連通的,並且所有結點的度數均爲偶數。
- 歐拉通路:無向圖 G =< V, E > 具有一條歐拉通路,當且僅當 G 是連通的,且僅有零個或兩個奇度數結點。
有向歐拉圖的判定定理
- 歐拉通路:有向圖 G 具有一條歐拉通路,當且僅當 G 是連通的,且除了兩個結點以外,其餘結點的入度等 於出度,而這兩個例外的結點中,一個結點的入度比出度大 1,另一個結點的出度比入度大 1。
- 歐拉回路:有向圖 G 具有一條歐拉回路,當且僅當 G 是連通的,且所有結點的入度等於出度。
本題思路
而本題,是無向圖的歐拉回路的判定,所以我們需要做兩件事情
- 判定該圖是否是連通的(使用並查集,有關並查集可以參考本文)
- 判定該圖是否所有的點的度數度數都是偶數(讀入時記錄)
完整代碼實現如下:
/*
歐拉圖:
設圖 G 是一個沒有孤立結點的圖,如果存在一條迴路經過圖中
的每條邊一次且僅一次,則稱這條迴路爲該圖的一條歐拉回路,
含有歐拉回路的圖稱爲歐拉圖
歐拉通路:
無向圖 G =< V, E > 具有一條歐拉通路,當且僅當 G 是連通的,且僅有零個或兩個奇度數結點
歐拉回路的判定定理:
無向圖 G =< V, E > 具有一條歐拉回路,當且僅當 G 是連通的,並且所有結點的度數均爲偶數。
採用並查集+度數的判定即可
*/
#include <iostream>
#include <vector>
using namespace std;
const int maxn = 1010;
vector<int> G[maxn]; // 保存圖
int father[maxn]; // 並查集的使用
int height[maxn]; // 保存每個結點的高度
int degree[maxn]; // 保存每個節點的度數
void Initial(int n)
{
fill(degree, degree + n, 0);
for (int i = 1; i <= n; i++)
{
father[i] = i;
height[i] = 1;
}
}
// 找父結點
int findFather(int x)
{
while (x != father[x])
x = father[x];
return x;
}
// 合併
void Union(int x, int y)
{
x = findFather(x);
y = findFather(y);
if (x != y)
{
if (height[x] < height[y])
{
father[x] = y;
}
else if (height[x] > height[y])
{
father[y] = x;
}
else
{
father[x] = y;
height[y]++;
}
}
}
int main()
{
freopen("data.txt", "r", stdin);
int n, m;
scanf("%d%d", &n, &m);
Initial(n); // 初始化
int u, v;
for (int i = 0; i < m; i++)
{
scanf("%d%d", &u, &v);
Union(u, v);
degree[u]++;
degree[v]++;
}
bool flag = true;
int root = findFather(1);
for (int i = 1; i <= n; i++)
{ // 判斷是否所有的點都在集合中
if (findFather(i) != root)
{
flag = false;
break;
}
}
for (int i = 1; i <= n; i++)
{
if (degree[i] % 2 != 0)
{
flag = false;
break;
}
}
if (flag)
{
printf("1");
}
else
{
printf("0");
}
return 0;
}