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;
}