POJ 1386 (欧拉路径+并查集)

题目的大意是:给出一些单词,问能否拼接成一串,使单词字母首尾相连。
例如,Sample中的:
acm
malform
mouse
我们可以构造出:
acm->malform->mouse,符合题目要求。

/*
1. 有向图G为欧拉图,当且仅当G的基图 连通,且所有顶点的入度等于出度。
2. 有向图G为半欧拉图,当且仅当G的基图连通,且存在一个顶点的入度比出度大1,
   一个顶点入度比出度小1,其它所有顶点的入度等于出度。
3. 无向图G为欧拉图,当且仅当G为连通的,且所有顶点度为偶数或者度为奇数的顶点个数为0或者2
4. 图的连通性可用并查集判断
*/
#include <iostream>
using namespace std;

const int MAX_LEN = 1002;
const int ALPHA_NUM = 26;
int degree[ALPHA_NUM], father[ALPHA_NUM];
char word[MAX_LEN];

int find_set(int i)
{
	if (i != father[i]){
		father[i] = find_set(father[i]);
	}
	return father[i];
// 	while (i != father[i]){
// 		i = father[i];
// 	}
// 	return father[i];
}

void make_set(int i)
{
	if (-1 == father[i]) father[i] = i;
}

void union_set(int a, int b)
{
	a = find_set(a);
	b = find_set(b);
	if (a != b){
		father[a] = b;
// 		if (rank[a] == rank[b]){
// 			father[a] = b;
// 			rank[a]++;
// 		}
// 		else if (rank[a] < rank[b]){
// 			father[a] = b;
// 		}
// 		else{
// 			father[b] = a;
// 		}
	}
}

int main()
{
	int c, n, i, j, len;
	scanf("%d", &c);
	for (i = 0; i < c; ++i){
		memset(degree, 0, sizeof(degree));
		memset(father, -1, sizeof(father));
		scanf("%d", &n);
		for (j = 0; j < n; ++j){
			scanf("%s", word);
			len = strlen(word);
			int a = word[0] - 'a';
			int b = word[len-1] - 'a';
			degree[a]++;
			degree[b]--;
			make_set(a);
			make_set(b);
			union_set(a, b);
		}

		int ne = 0, ng = 0, nl = 0;
		for (j = 0; j < ALPHA_NUM; ++j){
			if (degree[j] == 1){
				ng++;
			}
			else if (degree[j] == -1){
				nl++;
			}
			else if (degree[j] == 0){
				ne++;
			}
		}
		if (!((ng == 1 && nl == 1 && ne == ALPHA_NUM - 2)  //欧拉通路
			|| ne == ALPHA_NUM)){  //欧拉回路
			printf("The door cannot be opened.\n");
			continue;
		}

		for (j = 0; father[j] == -1; ++j);
		int root = find_set(j);
		for (j = j+1; j < ALPHA_NUM; ++j){
			if (father[j] == -1) continue;
			if (find_set(j) != root){   //所有的节点都有相同的祖先,则图是连通的
				printf("The door cannot be opened.\n");
				break;
			}
		}
		if (j == ALPHA_NUM){
			printf("Ordering is possible.\n");
		}
	}
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值