P1333 瑞瑞的木棍

瑞瑞的木棍

题目描述

瑞瑞有一堆的玩具木棍,每根木棍的两端分别被染上了某种颜色,现在他突然有了一个想法,想要把这些木棍连在一起拼成一条线,并且使得木棍与木棍相接触的两端颜色都是相同的,给出每根木棍两端的颜色,请问是否存在满足要求的排列方式。

例如,如果只有 2 根木棍,第一根两端的颜色分别为 red, blue,第二根两端的颜色分别为 red, yellow,那么 blue—red | red----yellow 便是一种满足要求的排列方式。

输入格式

输入有若干行,每行包括两个单词,表示一根木棍两端的颜色,单词由小写字母组成,且单词长度不会超过 10 10 10 个字母,最多有 250000 250000 250000 根木棍。

输出格式

如果木棒能够按要求排列,输出 Possible,否则输出 Impossible

样例 #1

样例输入 #1

blue red
red violet
cyan blue
blue magenta
magenta cyan

样例输出 #1

Possible

解析:

把每种颜色看成一个点,把木根看成边。即询问图中是否有欧拉路。

可以用并查集判断是否有多个连通块,以及度为奇数点的个数。

对于点的编号,map会超时,需要unordered_map,或者字典树。

代码:

#include
using namespace std;
typedef long long ll;
typedef double db;
#define fi first
#define se second
const int maxn = 1e6+10;
const int INF = 0x3f3f3f3f;
typedef pair<int, int> pii;

struct Trie{
	int nxt[maxn][26], tot;
	int id[maxn], idtot;
	void insert(string s){
		int p = 0;
		for(int i = 0; i < s.length(); i++){
			int ch = s[i] - 'a';
			if(!nxt[p][ch])
				nxt[p][ch] = ++tot;
			p = nxt[p][ch];
		}
		if(!id[p])
			id[p] = ++idtot;
	}
	int getid(string s){
		int p = 0;
		for(int i = 0; i < s.length(); i++){
			int ch = s[i] - 'a';
			p = nxt[p][ch];
		}
		return id[p];
	}
}trie;

struct node{
	int a, b;
	node(int a, int b) : a(a), b(b){}
	node(){}
};
vector<node> edg;
int fa[maxn];
int find(int x){
	return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);
}
void merge(int x, int y){
	int fx = find(x);
	int fy = find(y);
	if(fx != fy)
		fa[fx] = fy;
}
int deg[maxn];
string str;
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	
	while(cin >> str){
		trie.insert(str);
		int x = trie.getid(str);
		
		cin >> str;
		trie.insert(str);
		int y = trie.getid(str);
		
		deg[x]++;
		deg[y]++;
		edg.push_back(node(x, y));
	}
	int n = trie.idtot;
	for(int i = 1; i <= n; i++)
		fa[i] = i;
	for(int i = 0; i < edg.size(); i++){
		merge(edg[i].a, edg[i].b);
	}
	int flag = 1;
	for(int i = 1; i < n; i++){
		if(find(i) != find(i+1)){
			flag = 0;
			break;
		}
	}
	if(flag == 0){
		cout << "Impossible" << endl;
		return 0;
	}
	int cnt = 0;
	for(int i = 1; i <= n; i++){
		if(deg[i]%2 == 1)
			cnt++;
	}
	if(cnt == 0 || cnt == 2)
		cout << "Possible" << endl;
	else
		cout << "Impossible" << endl;
	
	return 0;
}

你可能感兴趣的:(算法,图论,c++)