因为前几天碰到这个题目,
项链(The Necklace,UVa 10054)
Description:
有一串珠子,每个珠子的前半部分和后半部分都有一种颜色。两个珠子颜色相同的部分,可以连到一起。给定一些珠子看是否能用所有这些珠子串成一个项链。
我建模之后发现因为每个项链左右可以互换,并且我最后只用看项链是否能够串成一串,于是当时我就选择这样建模从每个项链的左边到右边建一条无向边,最后看我这个图会不会在每条边只用一次的情况下构成环?
然后我就不会了,后来看了题解发现最终建模发现就是恩,求在我的每一条边只用一次的情况下能不能从一个点出发回到这个点。这就是欧拉回路的定义。
好了,著名,而又聪明的欧拉大人告诉我们求欧拉回路和欧拉道路用的一些充要条件。
欧拉回路:若图G中存在这样一条路径,使得它恰通过G中每条边一次,则称该路径为欧拉路径。若该路径是一个圈,则称为欧拉(Euler)回路。
- 无向图:
判定条件:一,连通图,二所有点的度数为偶数。
充分性证明:
首先,在图中任取一点,以该点为起点,沿着欧拉回路走,若当前顶点的出度为奇数,然后经过其他的顶点,注意到如果欧拉路径经过一个顶点(包括起点)那么它必定离开这个点,这样的话出度入度之和为偶数,直到所有的边被逐一走过,回路的终点在起点结束,所以入度加奇数次。这样的话起点的度数和就变成了偶数。
必要性证明:
首先,我们在连通图中任意寻找一条回路,如果这条回路就是欧拉回路,那么结论已经成立,否则我们删掉该回路中的所有边,出现孤立的顶点就忽略它,那么子图(不一定是联通的,并且仍然满足所有的顶点的度数都是偶数)与删掉的回路一定有有公共顶点(图的连通性保证了这一点),一直重复该过程,因为每次删除的边都为入度和出度一,这样的话所有这些删除的回路连起来必定为欧拉回路。
欧拉道路:若图G中存在这样一条路径,使得它恰通过G中每条边一次,则称该路径为欧拉道路。
欧拉道路的判定没有上面的回路那么严格。
判定条件:一,连通图,二,最多有两个点的度数为奇数,(若一个点度数为奇数则该点必定为欧拉道路的起点或者是终点)。
充要性证明,我们就这样么想若有两个点度数为奇数,那么我们将这两个点连起来就做成了一个欧拉回路。
若没有奇点着等同于欧拉回路。
上面题目的代码:
Hint:这个题目如果想AC的话就用我的输出格式吧,这个题目蜜汁奇怪。。。卡了半天,还要注意这儿的Map【i】【j】的含义是i颜色到j颜色之间有多少条边(考虑可能有多个珠子是一样的,所以要加加减减)
#include <iostream>
#include <cstdio>
const int MAXN = 1005;
using namespace std;
int Map[55][55],in[MAXN];
int N,T;
bool flag;
void dfs(int x){
for(int i = 1;i <= 50;i++){
if(Map[x][i]){
Map[x][i]--;
Map[i][x]--;
dfs(i);
printf("%d %d\n",i,x);
}
}
}
inline void init()
{
scanf("%d",&N);
int u,v;
flag = true;
for(int i = 1;i <= 50;i++){
in[i] = 0;
for(int j = 1;j <= 50;j++){
Map[i][j] = 0;
}
}
for(int i = 1;i <= N;i++){
scanf("%d %d",&u,&v);
Map[u][v]++;
Map[v][u]++;
in[v]++;
in[u]++;
}
for(int i = 1;i <= 50;i++)
if(in[i] % 2)
flag = false;
if(flag){
for(int i = 1;i <= 50;i++)
dfs(i);
}
else printf("some beads may be lost\n");
}
int main()
{
scanf("%d",&T);
for(int i = 1;i <= T;i++){
printf("Case #%d\n",i);
init();
if (i != T)
puts("");
}
return 0;
}