这里普及一下欧拉回路的知识。
欧拉道路是指从图中的任意一个点开始遍历,每条边恰好经过一次,这样的道路就是欧拉道路。
如果能从任意一个点出发,并回到这个点,每条边恰好经过一次,这样的道路是欧拉回路。
欧拉道路的判定:在无向图中,最多只有度数为奇数的点,则一定存在欧拉道路,并且要从一个奇点出发,到另一个奇点结束;如果全部都是偶数度数的点,那么就一定存在欧拉回路。对于有向图,最多有两个点的入度不等于出度,其中的一个点的入度必须比出度大1,这个点作为终点,另个一点一定要出度比入度大1,作为起点;如果不存在出度和入度不等的点,那么就存在欧拉回路。但是前提一定要图是连通的。
接下来就是题目:有n个珠子,每个珠子有两半,一半一个颜色,要求相邻的两个珠子挨着的部分是颜色相同的那一半,问按照这样的要求,能不能组成一个项链。
分析:开始很直接就是把珠子作为节点,很难搞定。后来看了神书,把颜色作为节点,珠子作为边,就是珠子上的一个颜色和另一个颜色连一条边,但是要注意的是,可能一种珠子可能有好多个,所以注意重边的处理!然后就是每条边走一次,相当于珠子用过一次,然后从任意一个颜色开始,最后走回这个颜色,正好就是欧拉回路!
代码:
#include <cstdio>
#include <cstring>
#include <stack>
using namespace std;
const int N = 60;
int n, T;
int g[N][N], edge[N];
bool iseu, vis[N][N];
struct E{ int u, v; } tmp;
stack <E> st;
void euler( int u ) {
for ( int v = 1; v <= 50; ++v ) if ( g[u][v] ) {
g[u][v]--; g[v][u] = g[u][v];
euler( v );
tmp.u = u, tmp.v = v;
st.push(tmp);
}
}
int main()
{
scanf("%d", &T);
int icase = 1;
while ( T-- ) {
scanf("%d", &n);
memset( g, 0, sizeof(g) );
memset( vis, 0, sizeof(vis) );
memset( edge, 0, sizeof(edge) );
int s, e;
for ( int i = 0; i < n; ++i ) {
scanf("%d%d", &s, &e);
edge[s]++, edge[e]++;
g[s][e]++;
g[e][s] = g[s][e];
}
iseu = true;
for ( int i = 1; i <= 50; ++i ) if ( edge[i] % 2 == 1 ) iseu = false;
printf("Case #%d\n", icase++ );
if ( !iseu )
printf("some beads may be lost\n");
else {
euler( s );
while ( !st.empty() ) {
tmp = st.top(); st.pop();
printf("%d %d\n", tmp.u, tmp.v);
}
}
if ( T > 0 ) printf("\n");
}
}