算法:trie树&并查集
难度:NOIP++ 思路不简单
说实话,这道题真的很难想到用trie树,反正不看题解我是想不到...
首先介绍一下 欧拉(通)路,额,主要是它的性质
**欧拉通路**
1、定义:通过图中每条边且只通过一次,并且经过每一顶点的通路。
2、判定方法
(1)无向图是否具有欧拉通路的判定: 图连通;图中只有0个或2个度为奇数的节点
(2)有向图是否具有欧拉通路的判定:图连通;除2个端点外其余节点入度=出度;1个端点入度比出度大1;一个端点入度比出度小1 或 所有节点入度等于出度。
**欧拉回路**
1、定义:通过图中每条边且只通过一次,并且经过每一顶点的回路。
2、判定方法
(1)无向图是否具有欧拉回路的判定:
(2)有向图是否具有欧拉回路的判定:图连通;所有节点入度等于出度。
好了,然后我们回来,发现它是欧拉通路!
考虑它的判定,然后就发现,我们想用并查集,联系起关系,
可是,字符串怎么玩并查集? (有可能可以吧)tao...
所以我们再一次用到trie树,插入时记录它们的编号,再去跑并查集,就好了。。。
为什么N只有>=500015才能过?????????
连续三次因为数组开的有问题而RE,MLE,WA,学弟带我学语法。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <queue>
#include <algorithm>
#define ll long long
#define N 500015
using namespace std;
char a[N],b[N];
int trie[N][30];
int vis[N],fa[N];
int cnt=1,v;
int insert(char *m)
{
int now = 0,len = strlen(m);
for (int i = 0;i < len;i++)
{
int temp=m[i]-'a';
if (!trie[now][temp])
{
vis[cnt]=0;
trie[now][temp]=cnt++;
}
now=trie[now][temp];
}
if (!vis[now]) vis[now] = ++v;
return vis[now];
}
int findf(int x)
{
if(x==fa[x]) return x;
return findf(fa[x]);
}
int degr[N];
void merg(int x,int y)
{
int u1=findf(x);
int u2=findf(y);
if(u1!=u2) fa[u1]=u2;
}
int main()
{
for(int i = 1;i <= N-3;i++)
{
fa[i]=i;
}
while(scanf("%s%s",a,b)!=EOF)
{
int t1=insert(a);
int t2=insert(b);
degr[t1]++;
degr[t2]++;
merg(t1,t2);
}
int ans=0;
for (int i = 1;i <= v;i++)
{
if (degr[i]%2==1) ans++;
if (ans>2||findf(1)!=findf(i))
{
puts("Impossible");
return 0;
}
}
if(ans==1) puts("Impossible");
else puts("Possible");
return 0;
}