【u008】瑞瑞的木棍

Time Limit: 1 second
Memory Limit: 128 MB

【问题描述】

 瑞瑞有一堆的玩具木棍,每根木棍的两端分别被染上了某种颜色,现在他突然有了一个想法,想要把这
些木棍连在一起拼成一条线,并且使得木棍与木棍相接触的两端颜色都是相同的,给出每根木棍两端
的颜色,请问是否存在满足要求的排列方式。
  例如,如果只有2根木棍,第一根两端的颜色分别为red,blue,第二根两端的颜色分别为red,yellow,
那么blue---red|red----yellow便是一种满足要求的排列方式。

【输入格式】

输入有若干行,每行包括两个单词,表示一根木棍两端的颜色,单词由小写字母组成,且单词长度不会超过10个字母,最多有250000根木棍。

【输出格式】

如果木棒能够按要求排列,输出Possible,否则输出Impossible

Sample Input1

blue red
red violet
cyan blue
blue magenta
magenta cyan

Sample Output1

Possible
【题解】
考的是hash函数。这里我们不去构造hash函数。而用字典树的方法来实现hash。即将单词这样的字符串转换为int类型。便于我们用下标访问。然后用木棍的信息建立一张图。即一根木棍就是一条边。然后需要连接起来。它的条件就是。这整张图为欧拉图。也就是一笔画。然后判断的方法是。
1.图是联通的。
2.统计所有的点的出度。如果出度全部为偶数或者恰好只有两个点为奇数。则可以一笔画。则能够把所有的木棍都连接起来。
//联通的话用并查集也可以。用dfs从任意一个点进行搜索然后看下能不能走到所有的点。也可以。但是推荐用dfs,因为可以一边统计出度信息。
然后如果不想打字典树。还有一种方法。就是把边的信息记录下来(记录的时候,两个字符串进行一下比较,小的放前面)。然后对边的信息进行排序。以边的左端点作为关键字排序。然后左端点相同的边就会紧邻在一起。我们把字符串编号一下就可以,然后还是一样建图即可。。
【代码】
#include <cstdio>
#include <cstring>

struct tree//用字典树的方法来获取某个单词的hash值。
{
	int hash;
	int next[27];
};

int tot = 0, ne[500001], first[500001], en[500001], totm = 0, chudu[500001] = { 0 },temp_tot,tot_v=1;
//用邻接表来存储图的信息。
bool visited[500001] = { 0 };
tree a[800001]; //用数组来模拟链表。

int sear_ch(char s[50])//用字典树。来获取s这个字符串对应的hash值。
{
	int l = strlen(s);//获取字符串的长度。
	int p = 1;//从根节点开始往下走
	for (int i = 1; i <= l; i++)
	{
		int x = s[i - 1] - 'a' + 1;//把小写字母和数字1..26对应
		if (a[p].next[x] == 0)//如果这个节点不存在。则新建一个节点、
		{
			tot_v++;
			a[p].next[x] = tot_v;
		}
		p = a[p].next[x];//一直往下走。
	}
	if (a[p].hash == 0)//如果这条路径(这个字符串)之前没人走过,则给其一个新的hash值
		a[p].hash = ++tot;
	return a[p].hash;//然后直接返回这个值就可以了。。
}

void add(int x, int y)//加一条从x指向y的边
{
	totm++;
	ne[totm] = first[x];//邻接表用的是链式存储的方式。
	first[x] = totm;
	en[totm] = y;
}

void dfs(int now)//这个程序会从最后一个点开始进行dfs看一下能不能走遍所有的点。
{
	temp_tot--;//找到了一个点,点的数目就减少。最后看temp_tot是否为0
	visited[now] = true;
	int temp = first[now];
	while (temp != 0)//用邻接表来获取这个点的出度。
	{
		chudu[now]++;//顺便记录出度
		int y = en[temp];
		if (!visited[y])//如果没有访问过就访问。
			dfs(y);
		temp = ne[temp];//寻找下一个出度
	}
}

int main()
{
	char s1[50], s2[50];
	while (scanf("%s%s", s1, s2) != -1)//多行输入
	{
		int x, y;
		x = sear_ch(s1);
		y = sear_ch(s2);
		add(x, y);
		add(y, x);
	}
	temp_tot = tot;//用来递减的temp
	if (tot>0) //如果什么都没输入也算是可以的。
		dfs(tot);
	if (temp_tot != 0)//如果图是不连通的则不能一笔画
	{
		printf("Impossible");
		return 0;
	}
	int oushu = 0, jishu = 0;//统计奇数的出度和偶数的出度的个数。
	for (int i = 1; i <= tot; i++)
		if ((chudu[i] % 2) == 0)//其实只要统计奇数的出度的个数就可以了。
			oushu++;
		else
			jishu++;
	if (jishu == 0 || jishu == 2)//可以看到只要统计奇数的出度个数就可以。。
		printf("Possible");
	else
		printf("Impossible");
	return 0;
}



原文地址:https://www.cnblogs.com/AWCXV/p/7632299.html