読者です 読者をやめる 読者になる 読者になる

Lilliput Steps

小さな一歩から着実に. 数学やプログラミングのことを書きます.

PCK 2011 本選 - 魔方陣

問題 : 魔方陣


解法 :

無向グラフ$G$ が直線グラフであるかを判定する問題.
各頂点の次数が$2$ 以下で, 大きさ$3$ 以上のサイクルを含まなければよいが, これはUnion-Find 木で効率的にチェックすることが可能である.
0 WA で早く実装できたので良い.

コード :

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <set>

using namespace std;

int par[100000];
void init(int n)
{
	for (int i = 0; i < n; i++){
		par[i] = i;
	}
}

int find(int x)
{
	if (par[x] == x) return (x);
	return (par[x] = find(par[x]));
}

bool same(int x, int y)
{
	return (find(x) == find(y));
}

void merge(int x, int y)
{
	x = find(x);
	y = find(y);
	if (x == y) return;
	if (rand() & 1) par[y] = x;
	else par[x] = y;
}

int main()
{
	int n, m;
	
	while (scanf("%d %d", &n, &m) && n){
		int deg[100000] = {0};
		set<pair<int, int> > used;
		init(n);
		
		bool ok = true;
		for (int i = 0; i < m; i++){
			int a, b;
			scanf("%d %d", &a, &b);
			--a; --b;
			deg[a]++;
			deg[b]++;
			if (deg[a] > 2 || deg[b] > 2) ok = false;
			if (used.find(make_pair(a, b)) != used.end()) ok = false;
			if (same(a, b)) ok = false;
			used.insert(make_pair(a, b));
			used.insert(make_pair(b, a));
			merge(a, b);
		}
		printf("%s\n", ok ? "yes" : "no");
	}	
}