参考博客:https://blog.csdn.net/lyy289065406/article/details/6647445
大致题意:
给定一些木棒,木棒两端都涂上颜色,求是否能将木棒首尾相接,连成一条直线,要求不同木棒相接的一边必须是相同颜色的
解题思路:
相同的颜色看作一个结点,木棒看作边,是否可以“一笔画”经过图中每个点,以及经过每条边一次。
无向图中存在欧拉路充要条件:
- 图联通 -> 并查集(需要压缩路径)
- 所有结点的度为偶数,或者有且只有两个度为奇数的节点
变长关键码,数据量过大,用map会超时,采用trie树,高效查询。
输出:
- POSSIBLE: 奇度数结点个数==0 或 ==2 且 图连通
- IMPOSSIBLE:奇度数结点个数==1 或 >=3 或 图不连通
//28076K 1329MS
#include <iostream>
#include <stdlib.h>
#include <string>
#include <cstring>
using namespace std;
const int large = 5e5;//结点
int tree[int(2e5)][30];//tree[i][j]表示节点i的第j个儿子的节点编号
bool flag[large];//表示以该节点结尾是一个单词
int ancestor[large];//并查集
int degree[large];//节点的度
int tot = 0;
int index = -1;
void init() {
memset(tree, -1, sizeof(tree));
memset(flag, 0, sizeof(flag));
memset(degree, 0, sizeof(degree));
tot = 0;
//每个点都是单独的集合,因此祖先为自身
for (int i = 0; i < large; ++i) {
ancestor[i] = i;
}
}
//true表示查找找到了,false插入
int find_insert(char *str) {
int len = strlen(str);
int root = 0;
int id;
index = -1; //记录节点下标
bool f = true;
for (int i = 0; i < len; ++i) {
id = str[i] - 'a';
if (tree[root][id] < 0) {
tree[root][id] = ++tot;
f = false;
}
root = tree[root][id];
}
flag[root] = true;
index = root;
return f;
}
//压缩路径的并查集查询
int find(int x) {
if (ancestor[x] != x)
ancestor[x] = find(ancestor[x]);
return ancestor[x];
}
//将两个集合合并
void union_set(int a, int b) {
int pa = find(a);
int pb = find(b);
ancestor[pb] = pa;
return;
}
int main() {
char f[11] = { '\0' };
char s[11] = { '\0' };
init();
//scanf_s("%s %s", &f, 11, &s, 11)
while (cin >> f >> s) {
int pa;
find_insert(f);
degree[index]++;
pa = index;
find_insert(s);
degree[index]++;
union_set(pa, index);
}
int num = 0;
int m = find(index);//经过压缩路径,所有的节点应该拥有同一个祖先
int cnt = 0;//访问节点的个数,如果和tot相等停止遍历
for (int i = 0; i < large; ++i) {
if (degree[i] == 0)
continue;
cnt++;
if (degree[i] & 1)
num++;
//多余两个度为奇数的点
if (num > 2) {
cout << "Impossible" << endl;
return 0;
}
if (flag[i]) {
int n = find(ancestor[i]);
//不连通
if (m != n) {
cout << "Impossible" << endl;
return 0;
}
}
if (cnt == tot)
break;
}
if (num == 1)
cout << "Impossible" << endl;
else
cout << "Possible" << endl;
return 0;
}