您的位置:首页 > 编程语言 > PHP开发

PKU 2513 ColorSticks 详细解答

2010-03-24 22:00 295 查看
该题 必须使用字典树(Trie Tree) 和 并查集(Disjointset) 和 欧拉通路 、 回路的相关知识来解答。】

不懂的同学先看下面的链接, 介绍了字典树、并查集、和欧拉通路回路 的 相关知识, 以及 代码模板。

字典树:http://blog.csdn.net/hongxdong/archive/2010/03/24/5413139.aspx

并查集:http://blog.csdn.net/hongxdong/archive/2010/03/24/5413445.aspx

欧拉通路回路:http://blog.csdn.net/hongxdong/archive/2010/03/24/5413711.aspx

我在想这题不用字典树, 用map<string , int> 代替字典树, 能不能通过啊? 试试。。。经过测试使用map 直接超时。

 

#include <iostream>
using namespace std;

const int MAXNUM = 500001;

// 并查集 的三个函数initialSet, findSet, unionSet.
int father[MAXNUM];
int rank[MAXNUM];
void initialSet(int i) //初始化并查集
{
father[i] = i;
rank[i] = 0;
}

int findSet(int i) //查找第i个 元素的集合号码, 回溯压缩路径.
{
if (i != father[i])
{
father[i] = findSet(father[i]);
}
return father[i];
}

void unionSet(int x, int y) // 合并两个集合, 通过rank[i] 判断元素加入集合的先后顺序.
{
if (x == y)
return;
if (rank[x] > rank[y])
{
father[y] = x;
}
else
{
if (rank[x] == rank[y])
{
rank[y]++;
}
father[x] = y;
}
}

// Trie Tree 字典树

const int kind=26;
int wkey = 0;  // 每个单词独一无二的key 的 初始化者.
struct node // 树的节点
{
int count;		// 记录字典中出现的次数
int key;        // 记录每个单词 的 独一无二的 key
node *next[kind];
node()
{
count=0;	// 创建结点即代表该单词出现一次
key = -1;
for(int i=0;i<kind;i++)
{
next[i]=NULL;	// 指针初始化为空
}
}
};
typedef node trietree;

int insert(trietree *root,char *word)  // 插入一个单词 并 返回该单词的key(key 从 1 开始计数, 所以上方的并查集father从1位置开始有效。)
{
node *local=root;
if(local==NULL)
{
local=new trietree();
root=local;
}

int i=0;		// counter
int branch;
while(word[i]!='/0')
{
branch=word[i]-'a';
if(local->next[branch]!=NULL)
{
//local->next[branch]->count++;
}
else
{
local->next[branch]=new trietree();
}
i++;
local=local->next[branch];
}
local->count++;
if (local->key == -1)
local->key = ++wkey;
return local->key;
}

int search(trietree *root,char *word) // 查找一个单词的key, 找不到单词则返回0
{
node *local=root;
if(local==NULL)
{
return 0;
}

int i=0;
int branch;
int ans;
while(word[i]!='/0')
{
branch=word[i]-'a';
if(local->next[branch]==NULL)
{
return 0;
}
i++;
local=local->next[branch];
}
return local->key;
}

int degree[MAXNUM]; // 记录每个颜色节点 的 度。

int main()
{
//freopen("in.txt", "r", stdin);
for (int i = 0; i < MAXNUM; i++)
{
initialSet(i);
degree[i] = 0;
}
char s1[12], s2[12];

trietree *root = new trietree();
int x, y;
while (scanf("%s %s", &s1, &s2) != EOF)
{
x = insert(root, s1);
y = insert(root, s2);
//cout<<"x = "<<x<<endl;
//cout<<"y = "<<y<<endl;
degree[x]++;
degree[y]++;
unionSet(findSet(x), findSet(y));
}

int sum = 0;

for (int i = 0; i < MAXNUM; i++) //判断度数为奇数的节点的个数
{
if (degree[i] % 2 == 1)
{
sum++;
}
}
//cout<<sum<<endl;
if (sum > 2) // 如果度数为奇数的度数的个数超过2 个, 表明图不可能存在欧拉通路
{
printf("Impossible/n");
}
else
{
//        for (int i = 0; i < 10; i++)
//        {
//            cout<<father[i]<<" ";
//        }
//        cout<<endl;
int base = findSet(1);
//cout<<"base = "<<base<<endl;
for (int i = 2; i < wkey; i++)  // 判断图是否为连通图.
{
if (findSet(i) != base)
{
printf("Impossible/n");
return 0;
}
}
printf("Possible/n");
}

return 0;
}

//
//
//
//POJ 2513 Colored Sticks C语言版
//2009年6月11日 23:18 Slyar 发表评论 阅读评论
//文章作者:Slyar 文章来源:Slyar Home (www.slyar.com) 转载请注明,谢谢合作。
//
//Trie树+并查集+欧拉通路
//
//
//Description
//
//You are given a bunch of wooden sticks. Each endpoint of each stick is colored with some color. Is it possible to align the sticks in a straight line such that the colors of the endpoints that touch are of the same color?
//
//Input
//
//Input is a sequence of lines, each line contains two words, separated by spaces, giving the colors of the endpoints of one stick. A word is a sequence of lowercase letters no longer than 10 characters. There is no more than 250000 sticks.
//
//Output
//
//If the sticks can be aligned in the desired way, output a single line saying Possible, otherwise output Impossible.
//
//Sample Input
//
//blue red
//red violet
//cyan blue
//blue magenta
//magenta cyan
//
//Sample Output
//
//Possible
//
//Slyar:说下题目大意,给出n根木棍,每根木棍两端都有颜色,颜色为小于10的字符串,问能否将所有的木棍排成一排,使得每两根木棍衔接的地方颜色相同。
//
//这题我一开始暴力做,很随意的就TLE了...看了Discuss发现要用什么"Trie"和"欧拉通路",还要用到前几天学会的并查集...晕死,根本不知道什么是"Trie"和"欧拉通路",遂Google了一下,得知"Trie"俗称字典树,具体内容完了发到博客上...欧拉通路完了也发博客上...本文发表2 weeks后应该可以搜索到...
//
//对于知道以上概念者,可以看出本题就是将所有的颜色看做节点,连接两种颜色的木棍看做节点之间的连边,判断无向图中是否存在欧拉通路,判断条件是:
//
//1、有且只有两个度为奇数的节点
//
//2、图是连通的
//
//由于节点是字符串,因此我们可以利用字典树将其转换成一个颜色序号。这样,统计每种颜色的出现次数就可以了。判断图是否连通,可以利用并查集:若最后所有节点在同一个集合,则图是连通的。
//
//eg. blue (magenta magenta) (cyan cyan) (blue blue) (red red) violet
//
//
//

// 下面转自 Slyar 的博客:http://www.slyar.com/blog/poj-2513-c.html

/*
PKU 2513
Slyar http://www.slyar.com/ */

//#include <stdio.h>
//#include <stdlib.h>
//
//#define MAX 500001
//
///* father[x]表示x的父节点 */
//int father[MAX];
///* rank[x]表示x的秩 */
//int rank[MAX];
///* degree记录节点的度 */
//int degree[MAX];
///* 记录字典树有效节点个数 */
//int num = 0;
//
///* 定义字典树节点类型 */
//typedef struct node
//{
//	int key;
//	struct node *next[26];
//}trie;
//
///* 创建根节点 */
//trie *root;
//
///* 创建新节点 */
//trie* New()
//{
//	int i;
//	trie *p;
//	p = (trie*) malloc(sizeof(trie));
//	/* 初始化节点为未访问 */
//	p->key = -1;
//	/* 初始化孩子指针 */
//	for (i = 0; i < 26; i++)
//	{
//		p->next[i] = NULL;
//	}
//	return p;
//}
//
///* 初始化 */
//void Make_Set(int x)
//{
//	father[x] = x;
//	rank[x] = 0;
//	degree[x] = 0;
//}
//
///* 查找x元素所在的集合,回溯时压缩路径 */
//int Find_Set(int x)
//{
//	if (x != father[x])
//	{
//		father[x] = Find_Set(father[x]);
//	}
//	return father[x];
//}
//
///* 合并x,y所在的集合 */
//void Union(int x, int y)
//{
//
//	if (x == y) return;
//	if (rank[x] > rank[y])
//	{
//		father[y] = x;
//	}
//	else
//	{
//		if (rank[x] == rank[y])
//		{
//			rank[y]++;
//		}
//		father[x] = y;
//	}
//}
//
///* 向以root为根的树中插入字符串s */
//int Insert(trie *root, char *s)
//{
//	int i;
//	trie *p = root;
//	for (i = 0; s[i] != '/0'; i++)
//	{
//		/* 节点若不存在则创建 */
//		if (p->next[s[i] - 'a'] == NULL)
//		{
//			p->next[s[i] - 'a'] = New();
//		}
//		/* 向下一层移动 */
//		p = p->next[s[i] - 'a'];
//	}
//	/* 得到并返回颜色节点序号 */
//	if (p->key == -1)
//	{
//		p->key = ++num;
//	}
//	return p->key;
//}
//
///* 主函数 */
//int main()
//{
//	int i, x, y, sum;
//	char s1[11], s2[11];
//
//	/* 初始化集合 */
//	for (i = 0; i < MAX; i++)
//	{
//		Make_Set(i);
//	}
//
//	/* 初始化根节点 */
//	root = New();
//
//	/* 处理字符串 */
//	while(scanf("%s%s", s1, s2) != EOF)
//	{
//		/* 插入颜色,得到颜色节点序号 */
//		x = Insert(root, s1);
//		y = Insert(root, s2);
//		/* 更新颜色节点的度 */
//		degree[x]++;
//		degree[y]++;
//		/* 合并两根木棍 */
//		Union(Find_Set(x), Find_Set(y));
//	}
//
//	sum = 0;
//
//	/* 求度为奇数的点的个数 */
//	for (i = 1; i < num; i++)
//	{
//		if(degree[i] % 2) sum++;
//	}
//
//	/* 若度大于2则肯定不可能 */
//	if (sum > 2)
//	{
//		printf("Impossible/n");
//	}
//	/* 否则考察图是否连通 */
//	else
//	{
//		/* 考察所有的点是否在一个集合 */
//		for (i = 2; i < num; i++)
//		{
//			if (Find_Set(i) != Find_Set(1))
//			{
//				printf("Impossible/n");
//				return 0;
//			}
//		}
//		printf("Possible/n");
//	}
//
//	//system("pause");
//	return 0;
//}


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息