格子游戏(很有意思的并查集)

1938: 格子游戏

Description

Alice和Bob玩了一个古老的游戏:首先画一个n * n的点阵,接着,他们两个轮流在相邻的点之间画上红边和蓝边。直到围成一个封闭的圈(面积不必为1)为止,“封圈”的那个人就是赢家。因为棋盘实在是太大了(n <= 200),他们的游戏实在是太长了!他们甚至在游戏中都不知道谁赢得了游戏。于是请你写一个程序,帮助他们计算他们是否结束了游戏?

Input

多组测试数据。

  输入数据第一行为两个整数n和m。m表示一共画了m条线。

        以后m行,每行首先有两个数字(x, y),代表了画线的起点坐标,接着用空格隔开一个字符,假如字符是"D ",则是向下连一条边,如果是"R "就是向右连一条边。输入数据不会有重复的边且保证正确。 

Output

 输出一行:在第几步的时候结束。假如m步之后也没有结束,则输出一行“draw”。 

Sample Input

3 5
1 1 D
1 1 R
1 2 D
2 1 R
2 2 D

Sample Output

4

分析:二维的并查集问题,只需将fa改为二维记录,不过具体思路需理解体会。

#include<iostream>
#include <cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn = 220;
int n, m;
struct uu
{//结构体记录父节点的坐标
	int x;
	int y;
}fa[maxn][maxn];
/*int find(int x)
{
	int r = x;
	while (r != fa[r])
	{
		r = fa[r];
	}
	int i = x, j;
	while (fa[i] != r)
	{
		j = fa[i];
		fa[i] = r;
		i = j;
	}
	return r;
}*/
uu find(uu k)
{
	if (k.x == fa[k.x][k.y].x&&k.y == fa[k.x][k.y].y)
	{
		return k;
	}
	else {
		fa[k.x][k.y] = find(fa[k.x][k.y]);//找到根节点
		return fa[k.x][k.y];
	}
}
int main()
{
	while (scanf("%d%d", &n, &m) != EOF)
	{
		int flag = 0, ans = 0;
		for (int i = 0; i <= n; i++)
		{
			for (int j = 0; j <= n; j++)
			{
				fa[i][j].x = i;
				fa[i][j].y = j;//初始化
			}
		}
		for (int i = 1; i <= m; i++)
		{
			char ke; int a, b;
			uu k1, k2;		
			scanf("%d%d", &a, &b);
			cin >> ke;
			if (flag)
				continue;
			if (ke == 'D')
			{//等于D画竖线
				k1 = find(fa[a][b]);
				k2 = find(fa[a + 1][b]);//因为竖线行加一
			}
			if (ke == 'R')
			{
				k1 = find(fa[a][b]);
				k2 = find(fa[a][b + 1]);//横线y+1
			}
			if (k1.x == k2.x&&k1.y == k2.y)
			{
				flag = 1; ans = i;//圈成一圈,记录flag = 1,ans = i用了i步。
			}
			else {
				fa[k1.x][k1.y] = k2;//还未围成一圈,将k1父结点设为k2
			}

		}
		if(flag)
			cout << ans << endl;
		else
		{
			cout << "draw" << endl;
		}
	}
    return 0;
}

猜你喜欢

转载自blog.csdn.net/fighting_yifeng/article/details/81429185