【u016】无序字母对

Time Limit: 1 second
Memory Limit: 128 MB

【问题描述】

给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒)。请构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现。


【输入格式】

第一行输入一个正整数n。 以下n行每行两个字母,表示这两个字母需要相邻。

【输出格式】

输出满足要求的字符串。 如果没有满足要求的字符串,请输出“No Solution”。 如果有多种方案,请输出前面的字母的ASCII编码尽可能小的(字典序最小)的方案

【数据规模】

Sample Input1

4
aZ
tZ
Xt
aX

Sample Output1

XaZtX

【样例说明】

不同的无序字母对个数有限,n的规模可以通过计算得到。
【题解】
把两个字母看做边的两端点。则所输入的n个字母对就是n条边。所求的字符串就是这n条边构成的图的欧拉路径。这里说的n+1个字符。如果它不是一条链。则一定是存在一个环的。

然后用存在欧拉路的定理先判定会不会有欧拉路;
即统计所有点的出度的奇偶个数。
如果奇数的出度数总数为0(全是偶数)或2.则存在欧拉路。
如果全是偶数。就从字典序最小的一个点开始dfs找就可以。
如果有两个奇数的点。就从字典序较小的那个奇数点开始dfs。
是一定能找到的。链的情况也可以包括。

其他情况都可以用欧拉图定理排除掉。
【代码】
#include <cstdio>
#include <stdlib.h>

int a[256][256] = { 0 }, n, w[256][256] = { 0 },chudu[256];
char temp[256];

void dfs(int x, int now)//现在到达x顶点。下一个点是第now个点
{
	if (now == n + 2)//如果已经找到第n+1个点了。
	{
		for (int i = 1; i <= n + 1; i++)//则输出之前记录的路径
			putchar(temp[i]);
		exit(0);//直接结束所有的程序。
	}
	for (int i = 1;i<= 255;i++)//寻找x的出度。并记录这个出度
		if (w[x][i] == 1)
		{
			w[x][i] = 0;
			w[i][x] = 0;//反向边也要置0.不然又会往回走。
			temp[now] = i;//记录路径
			dfs(i, now + 1);//继续搜索。
			w[x][i] = 1;
			w[i][x] = 1;
		}
}

int main()
{
	scanf("%d", &n);//输入n条边
	for (int i = 1; i <= n; i++)
	{
		char s[10];
		scanf("%s", s);//以字符串的形式输入。
		int x = s[0], y = s[1];//获取两个端点
		if (w[x][y] == 0)//如果没有重边
		{
			w[x][y] = 1;//记录边
			w[y][x] = 1;
			a[x][0]++;//记录其第a[x][0]个出度是什么
			a[x][a[x][0]] = y;
			a[y][a[y][0]] = x;
			chudu[x]++;//相应的出度递增。
			chudu[y]++;
		}
	}
	int jishu = 0,start = 0;//统计奇数出度的个数。以及从哪里开始进行dfs.
	for (int i = 1; i <= 255; i++)
	{
		if (chudu[i] > 0 && start == 0)//找到一个字典序最小的有出度的点。开始
			start = i;
		if ((chudu[i] % 2) == 1)//如果有奇数点。就从奇数点里面字典序最小的开始。
		{
			if (jishu == 0)
				start = i;
			jishu++;
		}
	}
	if (jishu != 0 && jishu != 2)//如果不全为偶数且奇数点的个数不为2.则输出无解信息。
	{
		printf("No Solution");
		return 0;
	}
	temp[1] = start;//否则从开始点开始搜寻欧拉路径 记录路径。
	dfs(start,2);
	return 0;
}


posted @ 2017-10-06 19:23  AWCXV  阅读(139)  评论(0编辑  收藏  举报