题目描述
Alice和Bob玩了一个古老的游戏:首先画一个 n×n 的点阵(下图 n=3 )。
接着,他们两个轮流在相邻的点之间画上红边和蓝边:
直到围成一个封闭的圈(面积不必为1)为止,“封圈”的那个人就是赢家。因为棋盘实在是太大了,他们的游戏实在是太长了!
他们甚至在游戏中都不知道谁赢得了游戏。
于是请你写一个程序,帮助他们计算他们是否结束了游戏?
输入格式
输入数据第一行为两个整数 n 和 m 。 n 表示点阵的大小, m 表示一共画了 m 条线。
以后 m 行,每行首先有两个数字 (x,y) ,代表了画线的起点坐标,接着用空格隔开一个字符,假如字符是 D ,则是向下连一条边,如果是 R 就是向右连一条边。
输入数据不会有重复的边且保证正确。
输出格式
输出一行:在第几步的时候结束。
假如 m 步之后也没有结束,则输出一行“draw”。
数据范围
1≤n≤200 ,
1≤m≤24000
输入样例:
3 5
1 1 D
1 1 R
1 2 D
2 1 R
2 2 D
输出样例:
4
算法分析
并查集(典型并查集判断是否存在环的问题)
1、将每个坐标看成一个点值,为了方便计算,将所有的坐标横纵坐标都减1,第一个位置即(1,1)看成是0,(1,2)看成是1,依次类推,将所有的坐标横纵坐标都减1后,假设当前点是(x,y),则该点的映射值是a = (x * n + y),
若向下画,则b = [(x + 1) * n + y],若向右画,则b = [x * n + y - 1]
2、枚举所有操作,通过并查集操作判断a和b是否在同一个集合,
若在同一个集合则标记此操作可以让格子形成环
若不在同一个集合,则需要将两个集合进行合并
代码
import java.util.Scanner;
import java.util.Arrays;
public class Main{
private static Scanner sc = new Scanner(System.in);
private static int[][] fa;
private static int n;
public static void main(String[] args){
int m;
n = sc.nextInt();
m = sc.nextInt();
init();
int x,y;
char ch;
int temp = m;
int res = 0;
while(temp-- != 0){
x = sc.nextInt();
y = sc.nextInt();
ch = sc.next().charAt(0);
if(res==0&&judge(x, y, ch))
res = m - temp;
}
if(res == 0)
System.out.println("draw");
else
System.out.println(res);
}
private static int[] getOtherPoint(int x, int y, char ch){
int[] ans = new int[2];
switch(ch){
case 'D':
ans[0] = x+1;
ans[1] = y;
break;
default:
ans[0] = x;
ans[1] = y+1;
}
return ans;
}
public static boolean judge(int x, int y, char ch){
int[] ot = getOtherPoint(x, y, ch);
int ox = ot[0];
int oy = ot[1];
int a = find(x, y);
int b = find(ox, oy);
if(a == b) return true;
fa[ox][oy] = a;
return false;
}
public static int find(int x, int y){
if(fa[x][y] != x*n+y){
fa[x][y] = find(fa[x][y]/n, fa[x][y]%n);
}
return fa[x][y];
}
public static void init(){
fa = new int[n+1][n+1];
for(int i = 0; i <= n; i++)
for(int j = 0; j <= n; j++){
fa[i][j] = i*n+j;
}
}
}