C语言DFS(7)___单词拼接(NYoj 99)

单词拼接

描述

给你一些单词,请你判断能否把它们首尾串起来串成一串。

前一个单词的结尾应该与下一个单词的道字母相同。

aloha

dog

arachnid

gopher

tiger

rat

可以拼接成:aloha.arachnid.dog.gopher.rat.tiger

输入
第一行是一个整数N(0<N<20),表示测试数据的组数

每组测试数据的第一行是一个整数M,表示该组测试数据中有M(2<M<1000)个互不相同的单词,随后的M行,每行是一个长度不超过30的单词,单词全部由小写字母组成。

输出
如果存在拼接方案,请输出所有拼接方案中字典序最小的方案。(两个单词之间输出一个英文句号".")

如果不存在拼接方案,则输出

***

样例输入
2
6
aloha
arachnid
dog
gopher
rat
tiger
3
oak
maple
elm
样例输出
aloha.arachnid.dog.gopher.rat.tiger
***

有向图G 为欧拉回路:

当且仅当G 的基图连通,且所有顶点的入度等于出度。

有向图G 为欧拉路:

当且仅当G 的基图连通,且只存在一个顶点u 的入度比出度大1、

只存在一个顶点v 的入度比出度小1,其它所有顶点的入度等于出度。

分析:此题应把单词的首字母和尾字母抽离出来,首字母出度+1,尾字母入度+1,这样就可以根据每个字母的出度和入度判断起点和终点。特别的,如果是欧拉回路的话,任何一点就可以作为起点,这时候我们按照题意选择字典顺序靠前的.

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

char str[1000][31];//存储字符串
bool used[1000]; //dfs的时候判断单词是否用过
int In[26];  //入度
int Out[26]; //出度
int s[1000];//在Judge中用来存放每个字符串的大小Size
int stack[1000];  //dfs存储结果
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");
	}
}
时间: 2024-07-31 20:03:38

C语言DFS(7)___单词拼接(NYoj 99)的相关文章

C语言DFS(6)___八皇后问题(Hdu 2612)

Problem Description 在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上. 你的任务是,对于给定的N,求出有多少种合法的放置方法. Input 共有若干行,每行一个正整数N≤10,表示棋盘和皇后的数量:如果N=0,表示结束. Output 共有若干行,每行一个正整数,表示对应输入行的皇后的不同放置数量. Sample Input 1 8 5 0 Sample Output 1 92 10 很经典的

NYOJ 99单词拼接(有向图的欧拉(回)路)

1 /* 2 NYOJ 99单词拼接: 3 思路:欧拉回路或者欧拉路的搜索! 4 注意:是有向图的!不要当成无向图,否则在在搜索之前的判断中因为判断有无导致不必要的搜索,以致TLE! 5 有向图的欧拉路:abs(In[i] - Out[i])==1(入度[i] - 出度[i])的节点个数为两个 6 有向图的欧拉回路:所有的节点都有In[i]==Out[i] 7 */ 8 #include<iostream> 9 #include<cstring> 10 #include<cs

nyoj 单词拼接(并查集判断连通性+欧拉路径)

这题还是比较难的. 首先建图方面,如果单纯的把单词作为点,能拼接的关系作为边,那么就是哈密顿图(每个点仅能走一次),难度比较大. 换一种思路,就是把每个单词看成一条有向边,由该单词的首字母指向尾字母. 那么这题便是欧拉图的问题了. 本质上采用的还是搜索,但是为了快速得到字典序最小的欧拉路径,首先要对单词集进行排序. 排完序后,用边集数组存图:再通过计算各点的出度与入度,同时判断基图(不考虑边的方向的图)的连通性,判断是否存在欧拉回路或欧拉通路. 如果存在欧拉回路,那么就从0开始搜索: 如果存在欧

NYOJ 单词拼接

# include<iostream> # include<string> # include<string.h> # include<queue> # include<stdio.h> # include<math.h> #include <algorithm> using namespace std; #define MAX 2005 int first[MAX],next[MAX],u[MAX],v[MAX],use

计蒜客 单词拼接

花椰菜君给了蒜头君 n 个单词,如果一个单词的最后一个字母和另一个单词的第一个字母相同,那么两个单词就可以连接在一起组成一个新的单词.现在花椰菜君想要蒜头君计算一下,给定的 n 个单词是否可以全部连接在一起. 输入格式 第一行输入一个整数 n,代表一共有 n 个单词(1≤n≤100,000). 接下来输入 nn行,每行输入一个单词.单词均由小写字母组成,每个单词长度不超过 20. 输出格式 输出一行,如果所有的单词都可以连接在一起并且可以形成一个环,那么输出Euler loop:如果所有单词都可

单词拼接 ----- 深搜

先判断这些单词能不能构成 接龙 , 能的话在排序 , 然后深搜确定接龙 . 题解 : 如果先确定所有单词的首尾字母的个数 , 如果首字母个数等于尾字母个数就不用管了 , 如果发现首字母比尾字母大1那个这个单词就是首位单词 , 末尾单词也是这样确定 , 如果发现有两个首尾的话  那么就不可能接龙成功  ,  如果成环的话 从字典序小的 单词里面找一个字母 , 排序 , 开始深搜  ,

【C语言学习笔记】字符串拼接的3种方法 .

昨天晚上和@buptpatriot讨论函数返回指针(malloc生成的)的问题,提到字符串拼接,做个总结. [cpp] view plaincopyprint? #include<stdio.h> #include<stdlib.h> #include<string.h> char *join1(char *, char*); void join2(char *, char *); char *join3(char *, char*); int main(void) {

C语言动态规划(8)___雇佣工人(HDU 1158)

Problem Description A project manager wants to determine the number of the workers needed in every month. He does know the minimal number of the workers needed in each month. When he hires or fires a worker, there will be some extra cost. Once a work

C语言贪心(2)___田忌赛马(Hdu 1052)

Problem Description Here is a famous story in Chinese history. "That was about 2300 years ago. General Tian Ji was a high official in the country Qi. He likes to play horse racing with the king and others." "Both of Tian and the king have t