题意:
有n根棍子,n<=250000,每根棍子两端各有一种颜色,如果两根棍子各有一个端点颜色相同,则可以把这两个端点连起来从而把这两个棍子连成线。现在给出每根棍子两端的颜色,问能否把所有棍子连成一条线。
思路:
首先,可以想到以颜色为顶点,棍子为边构图,则所有棍子能连成线等同于该图中存在欧拉通路。回忆一下欧拉通路的充要条件:(1)该图连通;(2)度数为奇数的顶点数为0或者2。其中条件(1)经常被粗心忽略掉,其实条件(1)才是最根本的条件。
接下来,问题就是对字符串的处理了。10个长度的字符串直接hash会爆内存,我采用的是字典树存储id值,新增一个颜色时,先在字典树中查找有没有,如果有,直接使用其id值,如果没有,在字典树中新增,总id值加1。这样一来,就可以转化为对于整数的处理问题了。
连通性用并查集判断,再记录每个顶点的度,就能判断是否存在欧拉通路。
最后,这道题存在空数据,空数据要输出Possible,这个trick要注意下。
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXA = 26; //可能出现的字符种类数,如果只有小写字母就是26种
const int MAXL = 12; //单词的最长长度
const int MAXN = 500010;
int degree[MAXN];
int father[MAXN];
struct Node
{
bool is_str; //标记该节点处是否构成单词
int id; //该单词的myhash值
Node* nxt[MAXA]; //儿子分支
};
int color; //当前的颜色数目,用与分配myhash值
void insert(Node *rt, const char *s)
{
if (rt == NULL || *s == 0)
return;
int i;
Node *p = rt;
while (*s != 0)
{
if (p->nxt[*s-'a'] == NULL)
{
Node *tmp = new Node;
for (i = 0; i < MAXA; ++i)
tmp->nxt[i] = NULL;
tmp->is_str = false;
p->nxt[*s-'a'] = tmp;
p = p->nxt[*s-'a'];
}
else
p = p->nxt[*s-'a'];
++s;
}
father[color] = color;
p->id = color++;
p->is_str = true;
}
int myhash(Node *rt, const char *s)
{
Node *p = rt;
char t[MAXL];
strcpy(t,s);
while (p != NULL && *s != 0)
{
p = p->nxt[*s-'a'];
++s;
}
if (p != NULL && p->is_str == true)
return p->id;
else
{
insert(rt,t);
return color-1;
}
}
int find(int x)
{
if (father[x] != x)
return x = find(father[x]);
else
return x;
}
void union_set(int x,int y)
{
int px = find(x);
int py = find(y);
if (px != py)
father[py] = px;
}
bool in_one_set(int x,int y)
{
return (find(x) == find(y));
}
void del(Node *rt)
{
int i;
for (i = 0; i < MAXA; ++i)
{
if (rt->nxt[i] != NULL)
del(rt->nxt[i]);
}
free(rt);
}
int main()
{
int i;
char s[MAXL],t[MAXL];
//初始化字典树
Node *rt = new Node;
for (i = 0; i < MAXA; ++i)
rt->nxt[i] = NULL;
rt->is_str = false;
memset(degree,0,sizeof(degree));
color = 0;
while (scanf("%s %s",s,t) != EOF)
{
int a = myhash(rt,s);
int b = myhash(rt,t);
++degree[a];
++degree[b];
union_set(a,b);
}
int res = 0;
for (i = 0; i < color; ++i)
{
if (degree[i] % 2 == 1)
++res;
}
if (color == 0)
printf("Possible\n");
else if (res == 0 || res == 2)
{
bool flag = false;
for (i = 0; i < color-1; ++i)
{
if (in_one_set(i,i+1) == false)
flag = true;
}
if (flag)
printf("Impossible\n");
else
printf("Possible\n");
}
else
printf("Impossible\n");
del(rt);
return 0;
}