NYOJ99 单词拼接

5 篇文章 0 订阅

题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=99

题目分析:
其实上这道题把给的单词转化成一个图,然后考察这个图是否具有一个欧拉回路。
一个图具有欧拉回路的充要条件是这个图是连通的,并且只有0或2个奇点。出度比入度大一的作为起点,出度比入度小一的作为终点。
一开始我把题目抽象错了,试图去把每个单词看成一个节点,然后抽象成图,这种做法是不对的,然而这种不对的想法纠结了我很久,以致于我一直坚持WA的提交。伤心啊。正确的应该是把字符抽象出来,单独的一个字符作为一个节点,来考虑出度和入度。如果一个字符出现在字符串首,那它的出度就+1,该字符通过这个字符串可以到达字符串尾的那个字符;如果出现在字符串尾,入度加1,字符串首的字符可通过该字符串达到该字符。想了好久才想明白。
为什么要用递归,这样节省空间,并且这里的话,递归的效率挺好的。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

char str[1000][31];
bool used[1000];
int In[26];
int Out[26];
int s[1000];//在Judge中用来存放每个字符串的大小Size
int stack[1000];
int n;

int compare(const void *a, const void *b)
{
	char *p1 = (char *)a;
	char *p2 = (char *)b;
	return strcmp(p1, p2);
}

int Judge()
{
	int i;
	int last = -1;
	int first = -1;
	for(i = 0; i < 26; ++i)
	{
		if(In[i] != Out[i])
		{
			//Out为在串首出现的次数,In为串尾出现的次数
			if(Out[i] - In[i] == 1 && first == -1)
				first = i;
			else if(Out[i] - In[i] == -1 && last == -1)
				last = i;
			else
				return -1;
		}
	}
	if(first > -1 && last > -1)
		return first;
	else if(first == -1 && last == -1)
	{
		for(i = 0; i < 26; ++i)
			if(In[i] != 0)
				return i;
	}
	else
		return -1;
}

bool DFS(char first, int Index)//有可能有多个连通区域
{
	if(Index == n)
		return true;
	int i;
	int b,e,m;
	b = 0;
	e = n - 1;
	while(b <= e)//二分法查找这个首字符,排序好的,肯定快啊。速度绝对比别人快2倍
	{
		m = (b + e)/2;
		if(str[m][0] == first)
			break;
		else if(str[m][0] > first)
			e = m - 1;
		else
			b = m + 1;
	}
	if(b > e)
		return false;
	//找到这个字符第一次出现的字符串
	while(str[m][0] == first && m >= 0)
		--m;
	for(i = m + 1; str[i][0] == first; ++i)
	{
		if(!used[i])
		{
			stack[Index] = i;
			used[i] = true;
			if(DFS(str[i][s[i] - 1], Index + 1))
				return true;
			used[i] = false;
		}
	}
	return false;
}

int main()
{
	int t;
	int i,first;
	scanf("%d", &t);
	while(t--)
	{
		scanf("%d", &n);
		for(i = 0; i < n; ++i)
			scanf("%s", str[i]);

		memset(used, 0, sizeof(used));
		memset(In, 0, sizeof(In));
		memset(Out, 0, sizeof(Out));
		qsort(str, n, 31 * sizeof(char), compare);
		for(i = 0; i < n; ++i)
		{
			s[i] = strlen(str[i]);
			++Out[str[i][0] - 'a'];
			++In[str[i][s[i] - 1] - 'a'];
		}

		first = Judge();
		if(first != -1 && DFS(first + 'a', 0))
		{
			for(i = 0; i < n - 1; ++i)
				printf("%s.", str[stack[i]]);
			printf("%s\n", str[stack[n - 1]]);
		}
		else
			printf("***\n");
	}
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值