题意:
给定一些木棒,木棒两端都涂上颜色,求是否能将所有木棒首尾相接,连成一条直线,要求不同木棒相接的一边必须是相同颜色的。
无向欧拉图:不存在或只存在两个奇度顶点
用并查集判断图的连通性 //判断是否只有一个根结点
用Trie或者hash给每种颜色编号
静态数组Trie
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 520000;
int du[maxn], f[maxn];
int n;
int findset(int x) {
return x==f[x]?x:f[x]=findset(f[x]);
}
//Trie
int ch[maxn][26];
int id[maxn];
int sz;
int Insert(char s[]) {
int u = 0, len = strlen(s);
for(int i=0; i<len; ++i) {
int c = s[i] - 'a';
if(!ch[u][c]) {
memset(ch[sz], 0, sizeof ch[sz] );
id[sz] = 0;
ch[u][c] = sz++;
}
u = ch[u][c];
}
if(!id[u]) id[u] = ++n;
return id[u];
}
void init() {
for(int i=0; i<maxn; ++i) {
f[i] = i;
du[i] = 0;
}
sz = 1;
n = 0;
memset(ch[0], 0, sizeof ch[0] );
}
int main() {
char str1[20], str2[20];
init();
while(~scanf("%s %s", str1, str2)) {
int a = Insert(str1); //同时返回编号
int b = Insert(str2);
du[a]++;
du[b]++;
int pa = findset(a);
int pb = findset(b);
if(pa != pb) {
f[pa] = pb;
}
}
int cnt_root = 0;
for(int i=1; i<=n; ++i){
if(f[i]==i){
if(++cnt_root>1){
puts("Impossible");
return 0;
}
}
}
int oddn = 0;
for(int i=1; i<=n; ++i) {
if(du[i]&1) oddn++;
}
if(oddn==0 || oddn==2) {
puts("Possible");
} else {
puts("Impossible");
}
return 0;
}
静态链式Trie
//Trie
int head[maxn];
int next[maxn];
char ch[maxn];
int id[maxn];
int sz;
int Insert(char s[]) {
int u = 0, v, len = strlen(s);
for(int i=0; i<len; ++i) {
bool flag = false;
for(v = head[u]; v!=0; v=next[v])
if(ch[v]==s[i]) {
flag = true;
break;
}
if(!flag) {
v = sz++;
ch[v] = s[i];
next[v] = head[u];
head[u] = v;
head[v] = 0;
}
u = v;
}
if(!id[u]) id[u] = ++n;
return id[u];
}
void init() {
for(int i=0; i<maxn; ++i) {
f[i] = i;
du[i] = 0;
}
sz = 1;
head[0] = next[0] = 0;
n = 0;
}
int main() {
char str1[20], str2[20];
init();
while(~scanf("%s %s", str1, str2)) {
int a = Insert(str1); //同时返回编号
int b = Insert(str2);
du[a]++;
du[b]++;
int pa = findset(a);
int pb = findset(b);
if(pa != pb) {
f[pa] = pb;
}
}
int cnt_root = 0;
for(int i=1; i<=n; ++i){
if(f[i]==i){
if(++cnt_root>1){
puts("Impossible");
return 0;
}
}
}
int oddn = 0;
for(int i=1; i<=n; ++i) {
if(du[i]&1) oddn++;
}
if(oddn==0 || oddn==2) {
puts("Possible");
} else {
puts("Impossible");
}
return 0;
}
hash
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 251000;
int du[maxn], f[maxn];
int n;
int findset(int x) {
return x==f[x]?x:f[x]=findset(f[x]);
}
void Union(int a, int b) {
if(f[a]==-1) f[a] = a;
if(f[b]==-1) f[b] = b;
int pa = findset(f[a]);
int pb = findset(f[b]);
if(pa!=pb)
f[pa] = pb;
}
// BKDR Hash Function
int Hash(char str[]) {
unsigned int seed = 131; // 31 131 1313 13131 131313 etc..
unsigned int hash = 0;
while (*str) {
hash = hash * seed + (*str++);
}
return (hash & 0x7FFFFFFF) % maxn;
}
int main() {
char str1[20], str2[20];
memset(du, 0, sizeof du );
memset(f, -1, sizeof f );
while(~scanf("%s %s", str1, str2)) {
int a = Hash(str1);
int b = Hash(str2);
du[a]++;
du[b]++;
Union(a, b);
}
int cnt_root = 0;
for(int i=1; i<maxn; ++i) {
if(f[i]!=-1) {
if(f[i]==i) cnt_root++;
}
}
if(cnt_root >1) {
puts("Impossible");
return 0;
}
int oddn = 0;
for(int i=1; i<maxn; ++i) {
if(f[i]!=-1 && du[i]&1) oddn++;
}
if(oddn==0 || oddn==2) {
puts("Possible");
} else {
puts("Impossible");
}
return 0;
}