目录
题目
题目描述
Alice和Bob玩了一个古老的游戏:首先画一个n × n的点阵(下图n = 3)
接着,他们两个轮流在相邻的点之间画上红边和蓝边:
直到围成一个封闭的圈(面积不必为1)为止,“封圈”的那个人就是赢家。因为棋盘实在是太大了(n ≤ 200),他们的游戏实在是太长了!他们甚至在游戏中都不知道谁赢得了游戏。于是请你写一个程序,帮助他们计算他们是否结束了游戏?
输入格式
输入数据第一行为两个整数n和m。m表示一共画了m条线。以后m行,每行首先有两个数字(x, y),代表了画线的起点坐标,接着用空格隔开一个字符,假如字符是"D ",则是向下连一条边,如果是"R "就是向右连一条边。输入数据不会有重复的边且保证正确。
输出格式
输出一行:在第几步的时候结束。假如m步之后也没有结束,则输出一行“draw”。
样例输入
3 5
1 1 D
1 1 R
1 2 D
2 1 R
2 2 D
样例输出
4
解析
题目意思:给一个矩形图加上边,判断什么时候能围城一个环。我们可以把棋盘每个点看做是图论中的一个点,给棋盘加边,其实就是在图论中给点加边。
每次连某条边,就将这条边的两个点进行集合合并。(起始的时候没有边,每个点都作为一个集合,加边即将两个点加入到一个集合中,其中可能有点已经在某个集合中,所以是将两边的集合进行合并)
当进行两个点合并时,如果两个点已经在同一个集合中,那么就说明已经构成了环。
此时这个图论是一个二维坐标下的,我们可以将其转换为一维坐标。
,其中 x 和 y 的下标需要从0开始,才能转换。
因此,总体来说是一个并查集的思路。并查集(基本原理+示例)_并查集 举例-CSDN博客
(图论的相关做法,例如dfs,bfs...因为题目需求,找第几步的时候结束,因此会非常耗时间,一步就要遍历一遍(我乱说的))
代码
import java.io.*;
public class Main {
static int N = 400040;
static int n,m,res;
static int[] p = new int[N];
public static void main(String[] args) throws IOException{
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String[] s = in.readLine().split(" ");
n = Integer.parseInt(s[0]);
m = Integer.parseInt(s[1]);
for(int i=0;i<n*n;i++) p[i] = i; // 初始化并查集
for(int i=1;i<=m;i++){
s = in.readLine().split(" ");
int x = Integer.parseInt(s[0])-1;
int y = Integer.parseInt(s[1])-1;
int pa = find(get(x,y)); // 找(x,y)的根节点
int pb; // (x`,y`)的根节点
if(s[2].equals("D")) pb = find(get(x+1,y)); // 向下
else pb = find(get(x,y+1)); // 向上
if(pa==pb){
res = i;
break;
}
p[pa] = pb;
}
if(res!=0) System.out.println(res);
else System.out.println("draw");
}
// 找根节点
public static int find(int u){
if(p[u]!=u) p[u] = find(p[u]);
return p[u];
}
// 二维坐标 -> 一维坐标
public static int get(int x,int y){
return x*n+y;
}
}
ps:其实我觉得40010就是够的,n最大就200,点数最多就40000,不知道为什么最后三个就会超。