您的位置:首页 > 其它

Poj 2513 Colored Sticks

2012-01-15 21:44 316 查看
题目大意:给出一些木棒,木棒数量不超过250000,每个木棒两端都涂有颜色,题目要求判断能否将所有木棒连成一条直线(颜色相同的木棒两端可以相连)。

思路:将木棒的两端看成节点,木棒看成边,则可以抽象出一个无向图,题目转换为判断无向图里是否存在一条欧拉路径。可以先用字典树为各个出现的颜色建索引,同时统计各个颜色出现的次数,即各个节点的度。根据欧拉路径成立的前提条件:奇数度的节点只能有0个或者2个,再利用并查集判断无向图的连通性,即可判断是否存在欧拉路径。

#include <iostream>
#include <stdio.h>
#include <memory.h>
using namespace std;
#define MAXN 26 //字符集大小
const int MAXSIZE = 500010;
typedef struct TrieNode {
int nodeId;
struct TrieNode *next[MAXN];
}TrieNode;
TrieNode Memory[1000010];
int allocp =0;
int idCtr;
/*初始化*/
void InitTrieRoot(TrieNode **pRoot) {
*pRoot = NULL;
idCtr=1;
}
/*创建新结点*/
TrieNode *CreateTrieNode() {
int i;
TrieNode *p;
p = &Memory[allocp++];
p->nodeId = 0;
for(i =0 ; i < MAXN ; i++) {
p->next[i] = NULL;
}
return p;
}
//插入	  
int InsertTrie(TrieNode **pRoot , char*s) {
int i , k;
TrieNode *p;
if(!(p =*pRoot)) {
p =*pRoot = CreateTrieNode();
}
i =0;
while(s[i]) {
k = s[i++] -'a'; //确定branch
if(!p->next[k])
p->next[k] = CreateTrieNode();
p = p->next[k];
}
if (p->nodeId==0) {
p->nodeId=idCtr;
idCtr++;
}
return p->nodeId;
}
int ctr[MAXSIZE];
int rank[MAXSIZE];//rank[x]表示x的秩
int parent[MAXSIZE];
//int n;//集合元素,从1到n
/* 查找x元素所在的集合,回溯时压缩路径*/
int FindSet(int x) {
if (x!=parent[x])
parent[x]=FindSet(parent[x]);
return parent[x];
}
//Union按秩合并,即合并的时候将元素少的集合合并到元素多的集合中,这样合并之后树的高度会相对较小
//通过秩rank的大小来衡量元素的多少
void Union(int root1, int root2) {
int x=FindSet(root1),y=FindSet(root2);
if (x==y)
return;
if (rank[x]>rank[y])
parent[y]=x;
else {
parent[x]=y;
if (rank[x]==rank[y])
++rank[y];
}
}
void Initialization() {
int i;
memset(rank,0,sizeof(rank));
for (i=1;i<MAXSIZE;i++)
parent[i]=i;
}
int main()
{
char start_str[12];
char end_str[12];
int start_id,end_id,i,j;
TrieNode *root;

InitTrieRoot(&root);
memset(ctr,0,sizeof(ctr));
Initialization();
while (scanf("%s%s",&start_str,&end_str)!=EOF) {
start_id=InsertTrie(&root,start_str);
end_id=InsertTrie(&root,end_str);
//	printf("%d %d\n",start_id,end_id);
ctr[start_id]++;
ctr[end_id]++;
Union(start_id,end_id);
}
j=FindSet(1);
for (i=1;i<idCtr;i++) {
if (FindSet(i)!=j) {
printf("Impossible\n");
return 0;
}
}
j=0;
for (i=1;i<idCtr;i++) {
if (ctr[i]%2!=0)
j++;
}
if (j<3)
printf("Possible\n");
else
printf("Impossible\n");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: