题目 3114: 信息学奥赛一本通T1347-格子游戏——并查集

目录

题目

解析

代码


题目

题目描述

        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)\rightarrow x*n+y  ,其中 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,不知道为什么最后三个就会超。

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值