POJ2513(欧拉路_trie树_并查集)

参考博客: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;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值