AtCoder Beginner Contest 339

[ABC339B] Langton's Takahashi

题面翻译

有一个 n n n m m m 列的有色网格图。网格图的位置按照二维数组定义(而非笛卡尔坐标系)。初始时网格图上每个格子的颜色都是白色的。

这个网格图是循环定义的。换言之, ( n , i ) (n, i) (n,i) 的下面是 ( 1 , i ) (1, i) (1,i) ( i , m ) (i, m) (i,m) 的右面是 ( i , 1 ) (i, 1) (i,1)。以此类推。

Takahashi 现在站在 ( 1 , 1 ) (1, 1) (1,1),脸朝上。他(请原谅我不知道他是男女)会执行下面操作 n n n 次:

  • 如果当前格子是白色的,Takahashi 会将它染黑,顺时针转 90 ° 90 \degree 90° 后走一格。

  • 如果当前格子是黑色的,Takahashi 会将它染白,逆时针转 90 ° 90 \degree 90° 后走一格。

输入一行 n , m , k n, m, k n,m,k,你需要输出最终棋盘的状态。用 # \texttt{\#} # 表示黑色, . \texttt{.} . 表示白色。

1 ≤ n , m ≤ 100 1 \le n, m \le 100 1n,m100 k ≤ 1000 k \le 1000 k1000

题目描述

$ H $ 行 $ W $ 列のグリッドがあり、はじめすべてのマスが白で塗られています。グリッドの上から $ i $ 行目、左から $ j $ 列目のマスを $ (i,\ j) $ と表記します。

このグリッドはトーラス状であるとみなします。すなわち、各 $ 1\ \leq\ i\ \leq\ H $ に対して $ (i,\ W) $ の右に $ (i,\ 1) $ があり、各 $ 1\ \leq\ j\ \leq\ W $ に対して $ (H,\ j) $ の下に $ (1,\ j) $ があるとします。

高橋君が $ (1,\ 1) $ にいて上を向いています。高橋君が以下の操作を $ N $ 回繰り返した後のグリッドの各マスがどの色で塗られているか出力してください。

  • 現在いるマスが白で塗られている場合は、現在いるマスを黒に塗り替え、時計回りに $ 90^\circ $ 回転し、向いている方向に $ 1 $ マス進む。そうでない場合は、現在いるマスを白に塗り替え、反時計回りに $ 90^\circ $ 回転し、向いている方向に $ 1 $ マス進む。

输入格式

入力は以下の形式で標準入力から与えられる。

$ H $ $ W $ $ N $

输出格式

$ H $ 行出力せよ。$ i $ 行目には長さ $ W $ の文字列であって、$ (i,\ j) $ が白で塗られている場合は $ j $ 文字目が .、黒で塗られている場合は $ j $ 文字目が # であるものを出力せよ。

样例 #1

样例输入 #1

3 4 5

样例输出 #1

.#..
##..
....

样例 #2

样例输入 #2

2 2 1000

样例输出 #2

..
..

样例 #3

样例输入 #3

10 10 10

样例输出 #3

##........
##........
..........
..........
..........
..........
..........
..........
..........
#........#

提示

制約

  • $ 1\ \leq\ H,\ W\ \leq\ 100 $
  • $ 1\ \leq\ N\ \leq\ 1000 $
  • 入力される数値はすべて整数

Sample Explanation 1

グリッドの各マスは操作によって以下のように変化します。 .... #... ##.. ##.. ##.. .#.. .... → .... → .... → .#.. → ##.. → ##.. .... .... .... .... .... ....

AC代码

import java.util.Scanner;
//旋转问题
public class B {
    static int N = 1010;
    static char[][] g = new char[N][N];
    static int[] dx = {-1, 0, 1, 0};//顺时针: 上右下左  dx是行:上下动  dy是列:左右动
    static int[] dy = {0, 1, 0, -1};

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int h = sc.nextInt();
        int w = sc.nextInt();
        int t = sc.nextInt();
        for (int i = 0; i < h; i++) {//初始化地图
            for (int j = 0; j < w; j++) {
                g[i][j] = '.';
            }
        }
        int x = 0, y = 0, p = 0;//x,y是当前坐标,p使得x,y顺时针旋转或者逆时针旋转
        while (t-- > 0) {
            if (g[x][y] == '.') {
                g[x][y] = '#';
                p = (p + 1) % 4;//顺时针旋转
            } else {
                g[x][y] = '.';
                p = (p - 1 + 4) % 4;//逆时针旋转 解释p-1+4  : -1是指逆时针旋转,+4是偏移量防止越界
            }
            x = (x + dx[p] + h) % h;//%h 是走到边界后再从相对的边界出来
            y = (y + dy[p] + w) % w;
        }
        for (int i = 0; i < h; i++) {//输出结果
            for (int j = 0; j < w; j++) {
                System.out.print(g[i][j]);
            }
            System.out.println();
        }


    }
}

[ABC339D] Synchronized Players

题面翻译

一个 n ( 2 ≤ n ≤ 60 ) n(2\le n \le 60) n(2n60) n n n 列的地图,.代表一个空的宿舍,#代表一个障碍物,P代表一个人正在这个宿舍中,地图中有且只有 2 2 2 人。

你可以选择让这 2 2 2 个人同时向上下左右中的一个方向移动,若一个人移动后走到了边界外或者障碍物上,他就不会移动。

问最多要移动几次,可以把这 2 2 2 个人移动到同一个宿舍中。若不可能移动到同一个宿舍,输出 -1

题目描述

$ N $ 行 $ N $ 列のグリッドがあり、各マスは空きマスか障害物のあるマスのいずれかです。グリッドの上から $ i $ 行目、左から $ j $ 列目のマスを $ (i,\ j) $ と表記します。

また、$ 2 $ 人のプレイヤーがグリッド上の相異なる空きマス上におり、各マスの情報は $ N $ 個の長さ $ N $ の文字列 $ S_1,\ S_2,\ \ldots,\ S_N $ として以下の形式で与えられます。

  • $ S_i $ の $ j $ 文字目が P であるとき、$ (i,\ j) $ は空きマスであり、プレイヤーがいる
  • $ S_i $ の $ j $ 文字目が . であるとき、$ (i,\ j) $ は空きマスであり、プレイヤーがいない
  • $ S_i $ の $ j $ 文字目が # であるとき、$ (i,\ j) $ は障害物のあるマスである

以下の操作を繰り返し $ 2 $ 人のプレイヤーを同じマスに集めるために必要な操作回数の最小値を求めてください。ただし、操作の繰り返しにより $ 2 $ 人のプレイヤーを同じマスに集めることができない場合には -1 を出力してください。

  • 上下左右のいずれかの方向を決める。そして各プレイヤーはともにその方向に隣接するマスへの移動を試みる。各プレイヤーは移動先のマスが存在し、かつ空きマスであるならば移動し、そうでないならば移動しない。

输入格式

入力は以下の形式で標準入力から与えられる。

$ N $ $ S_1 $ $ S_2 $ $ \vdots $ $ S_N $

输出格式

答えを出力せよ。

样例 #1

样例输入 #1

5
....#
#..#.
.P...
..P..
....#

样例输出 #1

3

样例 #2

样例输入 #2

2
P#
#P

样例输出 #2

-1

样例 #3

样例输入 #3

10
..........
..........
..........
..........
....P.....
.....P....
..........
..........
..........
..........

样例输出 #3

10

提示

制約

  • $ N $ は $ 2 $ 以上 $ 60 $ 以下の整数
  • $ S_i $ は長さ $ N $ の P, ., # からなる文字列
  • $ S_i $ の $ j $ 文字目が P であるような組 $ (i,\ j) $ の個数はちょうど $ 2 $ つ

Sample Explanation 1

はじめに $ (3,\ 2) $ にいるプレイヤーをプレイヤー $ 1 、 、 (4,\ 3) $ にいるプレイヤーをプレイヤー $ 2 $ とします。 例えば以下のようにすることで、$ 3 $ 回の操作で $ 2 $ 人のプレイヤーが同じマスに集まります。 - 左を選択する。プレイヤー $ 1 $ は $ (3,\ 1) $ に移動し、プレイヤー $ 2 $ は $ (4,\ 2) $ に移動する。 - 上を選択する。プレイヤー $ 1 $ は移動せず、プレイヤー $ 2 $ は $ (3,\ 2) $ に移動する。 - 左を選択する。プレイヤー $ 1 $ は移動せず、プレイヤー $ 2 $ は $ (3,\ 1) $ に移動する。

AC代码

import java.util.*;

//bfs问题
public class D {
    static int N = 65, n;
    static char[][] g = new char[N][N];//地图
    static int[][][][] d = new int[N][N][N][N];
    static int[][][][] v = new int[N][N][N][N];
    static int[] dx = {1, -1, 0, 0};
    static int[] dy = {0, 0, 1, -1};

    static void bfs(int[] x, int[] y) {
        Deque<Point> q = new ArrayDeque<>();
        d[x[0]][y[0]][x[1]][y[1]] = 0;//起点步数为1
        q.offer(new Point(x[0], y[0]));//P起始位置入队
        q.offer(new Point(x[1], y[1]));
        v[x[0]][y[0]][x[1]][y[1]] = 1;//标记
        while (!q.isEmpty()) {
            Point t1 = q.poll();
            Point t2 = q.poll();
            for (int i = 0; i < 4; i++) {
                int newX1 = t1.x + dx[i];
                int newY1 = t1.y + dy[i];
                int newX2 = t2.x + dx[i];
                int newY2 = t2.y + dy[i];
                if (newX1 < 0) newX1 = 0;//超越地图则回去
                if (newX2 < 0) newX2 = 0;
                if (newY1 < 0) newY1 = 0;
                if (newY2 < 0) newY2 = 0;
                if (newX1 >= n) newX1 = n - 1;
                if (newX2 >= n) newX2 = n - 1;
                if (newY1 >= n) newY1 = n - 1;
                if (newY2 >= n) newY2 = n - 1;

                if (g[newX1][newY1] == '#') {//遇到石头则不动
                    newX1 = t1.x;
                    newY1 = t1.y;
                }
                if (g[newX2][newY2] == '#') {
                    newX2 = t2.x;
                    newY2 = t2.y;
                }
                if (v[newX1][newY1][newX2][newY2] == 1) continue;//曾经走过就不再走了

                d[newX1][newY1][newX2][newY2] = d[t1.x][t1.y][t2.x][t2.y] + 1;//次数加1
                v[newX1][newY1][newX2][newY2] = 1;//标记已走
                q.offer(new Point(newX1, newY1));//入队
                q.offer(new Point(newX2, newY2));
            }
        }


    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        for (int i = 0; i < n; i++) {
            g[i] = sc.next().toCharArray();//读入地图
        }
        int[] x = new int[2];//存P下标
        int[] y = new int[2];
        int k = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (g[i][j] == 'P') {
                    x[k] = i;
                    y[k++] = j;
                }
            }
        }

        for (int i = 0; i < n; i++) {//把d输出初始化为最大值,因为要求最小值
            for (int j = 0; j < n; j++) {
                for (int l = 0; l < n; l++) {
                    for (int m = 0; m < n; m++) {
                        d[i][j][l][m] = Integer.MAX_VALUE;
                    }
                }
            }
        }
        bfs(x, y);
        int res = Integer.MAX_VALUE;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                res = Math.min(res, d[i][j][i][j]);//相遇时走的最小次数
            }
        }


        if (res == Integer.MAX_VALUE) {
            System.out.println(-1);//相遇不到
        } else {
            System.out.println(res);
        }


    }
}

class Point {
    int x, y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值