题意:有一串珠子,每个珠子的前半部分和后半部分都有一种颜色。两个珠子颜色相同的部分,可以连到一起。给定一些珠子看是否能用所有这些珠子串成一个项链。
思路:将每个颜色看做一个顶点,每个珠子对应一种颜色到另一颜色的无向边。每个珠子只能用一次,相当于每条边只能用一次。欧拉回路。不过不同的是,这道题需要输出欧拉回路的路径,而且下一路径的起点必须是上一路径的重点。我觉得难点是在这个路径的输出上。 开始的时候我是在dfs()里用 printf("%d%d",n,i); dfs(i);(方式1) 这样是不能满足要求的。比如对边集合 1 1、1 2、2 1、2 3、3 2来说,上述代码就会打印出1 1、1 2、2 1、2 3、3 2。而是应该用 dfs(i); printf("%d%d",n,i); (方式2)输出路径,这样的话,每次递归 dfs(i); 时,函数dfs(n); 的栈帧相当于入栈了,即相当于边 n-i 入栈。一直到遇到一个没有邻边没被访问的顶点时,才开始弹栈输出边。比如上述示例,开始压栈1 1、1 2、2 1,再dfs(1)时发现1顶点没有未访问的边了,于是弹栈输出边2-1,继续找2的邻接边,发现是3,压栈2 3、3 2,dfs(2)发现没有未访问的边,弹栈输出。此外,由于要求路径的起点和上一路径的终点要相同,所有输出的时候应改为 printf("%d %d",i,n); 这个也好理解,比如之前实例是压栈1 1、1 2、2 1,然后发现需要弹栈输出了,因为顺着到达1这个没有未访问边的顶点时,路径上是首尾相接的,所以你反着输出也就正好是首尾相接的,比如如果只有这三条边的话,你反着输出就是1-2、2-1、1-1。
更直观的是对于欧拉道路的输出,用 dfs(i); printf("%d %d",i,n); 相当于你从起点首尾相接地走出一条到终点的道路,然后到终点时,发现没有未访问的边则开始回退,用print(i,n)将边的顶点反过来,相当于输出一条从终点首尾相接回退到起点的路径。
对于路径输出的理解还有一个例子,比如有边集合1 3、3 3、3 5,输出欧拉道路。用方式1输出的话,意思是每遇到一条路径时就输出,这样不能保证连续,比如这里会输出1 3、3 3、3 5,但如果重点改为2呢,即5改为2,则输出1 3、3 2、3 3,相当于从起点到终点后再回退到上一顶点打印另一条路径。而用方式2输出,它是在遇到一个没有邻边的顶点时才输出,输出的是3 5、3 3、1 3 和 3 2、3 3、1 3。需要首尾相接,就将 n,i 调换为 i,n 。
针对这道题,我是判断了连通性,而且判断连通性和找路径是在一起进行的,所以用一个数组保存了路径,在判断连通后才输出。开始觉得是首尾相接的,就只保存一个点,然后输出时用print(i,i+1); 结果出现错误,很难发现~
Code:
#include<stdio.h>
#include<string.h>
bool solve();
void dfs(int n);
int graph[51][51];
int du[51];
int path[1010*2];
int len;
int main()
{
//freopen("10054.in","r",stdin);
//freopen("10054.out","w",stdout);
int t;
scanf("%d",&t);
int num=0;
while(t-->0)
{
num++;
memset(graph,0,sizeof(graph));
memset(du,0,sizeof(du));
len=0;
int n;
scanf("%d",&n);
for(int i=0;i<n;++i)
{
int a,b;
scanf("%d%d",&a,&b);
du[a]++;
du[b]++;
graph[a][b]++;//增加一条无向边
//graph[b][a]=graph[a][b];
graph[b][a]++;
}
if(num!=1) printf("\n");
printf("Case #%d\n",num);
int len=0;
if(solve()==false) printf("some beads may be lost\n");
}
return 0;
}
bool solve()
{
//判定顶点度数
for(int i=1;i<=50;++i)
{
if(du[i]%2==0) continue;
else return false;
}//printf("ok\n");
//判定连通性
int cnt=0;//连通块个数
for(int i=1;i<=50;i++)
{
if(du[i])//存在该颜色
{
cnt++; dfs(i);
}
}
if(cnt>1) return false;
//print
//printf("len:%d\n",len);
for(int i=0;i<len-1;i=i+2)
{
printf("%d %d\n",path[i],path[i+1]);
}
//printf("%d %d\n",path[len-1],path[0]);
return true;
}
void dfs(int n)
{
for(int i=1;i<=50;i++)
{
if(graph[n][i])
{
graph[n][i]--;
//graph[i][n]=graph[n][i];
graph[i][n]--;
du[n]--;
du[i]--;
//path[len++]=n;
dfs(i);
path[len++]=i;
path[len++]=n;
}
}
}