今天学了个欧拉回路~
理解起来感觉不是很难,证明竟然也看懂了。
首先,得认识这么几个名词:
1.欧拉路径:图中存在一条从s到t的路径,使这条路径经过了所有的边,且每条边之经过一次。简单来说就是这张图可以一笔画出来.
2.欧拉回路:就是欧拉回路中s == t。
3.欧拉图:存在欧拉回路的图。
4.半欧拉图:存在欧拉路径但是不存在欧拉回路的图。
然后,有这么几个结论:
1.欧拉图一定是连通的。(废话)
2.欧拉图中每一个点的度数都是偶数。
因为对于每一个点,一定是从一条边进入,从一条边离开,而且这些边都不重,所以每一条边的度数都为偶数。
3.半欧拉图中只有两个点的度数为奇数,其余点的度数为偶数,而且这两个点一个是起点,一个是终点。
起点的入度比出度少1,终点的入度比出度多1.
4.有向图为欧拉图,当且仅当所有点的入度等于出度。
然后怎么找欧拉回路:
以无向图为例:伪代码
1 void dfs(int x) 2 { 3 对于从x出发的所有边(x, y) 4 如果(x, y)没被访问 5 标记(x, y),(y, x)为已访问 6 dfs(y) 7 把x放入栈 8 } 9 10 int main() 11 倒序输出栈中所有元素
有向图类似。
考虑这道题,有个非常烦人的一点:输出字典序最小的。
然后我就想到了这么个方法:用邻接矩阵存图。但这样只有在n比较小的时候才能过……
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cctype> 8 #include<stack> 9 #include<queue> 10 #include<vector> 11 using namespace std; 12 #define enter puts("") 13 #define space putchar(' ') 14 #define Mem(a, x) memset(a, x, sizeof(a)) 15 #define rg register 16 typedef long long ll; 17 typedef double db; 18 const int INF = 0x3f3f3f3f; 19 const db eps = 1e-8; 20 const int maxn = 505; 21 inline ll read() 22 { 23 ll ans = 0; 24 char ch = getchar(), las = ' '; 25 while(!isdigit(ch)) las = ch, ch = getchar(); 26 while(isdigit(ch)) ans = ans * 10 + ch - '0', ch = getchar(); 27 if(las == '-') ans = -ans; 28 return ans; 29 } 30 inline void write(ll x) 31 { 32 if(x < 0) putchar('-'), x = -x; 33 if(x >= 10) write(x / 10); 34 putchar(x % 10 + '0'); 35 } 36 37 int m, n = -1; 38 int G[maxn][maxn], du[maxn]; 39 40 stack<int> st; 41 void euler(int now) 42 { 43 for(int i = 1; i <= n; ++i) 44 if(G[now][i]) 45 { 46 G[now][i]--; G[i][now]--; 47 euler(i); 48 } 49 st.push(now); 50 } 51 52 int main() 53 { 54 m = read(); 55 for(int i = 1; i <= m; ++i) 56 { 57 int x = read(), y = read(); 58 n = max(n, max(x, y)); 59 G[x][y]++; G[y][x]++; 60 du[x]++; du[y]++; 61 } 62 bool flg = 1; 63 for(int i = 1; i <= n && flg; ++i) if(du[i] & 1) {euler(i); flg = 0;} 64 if(flg) euler(1); 65 while(!st.empty()) {write(st.top()); enter; st.pop();} 66 return 0; 67 }