电路维修.java 3.7 KB
Newer Older
qq_36480062's avatar
c  
qq_36480062 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
package DFS.双端队列;

import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Scanner;

/**
 * 超级复杂...
 * https://blog.csdn.net/qq_30277239/article/details/104719098
 * 当一个图的边权只可能是0或者1时,就可以使用双端队列BFS求解
 * 本题求从左上角到右下角要想连通的最小旋转次数,
 * 一个方格的对角线之间,如果有连线,就可以被视为这两点之间的边权长度是0,
 * 如果需要旋转才有连线,则视边权的长度为1,
 * 所以本题就转化为了一个边权只有01两种情况的最短路问题。
 * 为什么BFS可以解决边权不等的最短路问题,
 * 可以说是此时BFS的队列相当于dijkstra算法中的优先级队列,
 * 是单调的,也是由BFS队列中元素的两段性和单调性决定的。
 * dijkstra算法在非负权图都是正确的,但需要建图
 * 经典做法,双端队列
 * 使用方法:拓展的节点,边权为0插入队头,边权为1插入队尾,取只取队头
 * 转化为Dijkstra算法,把问题转化为Dijkstra算法能解决的问题
 * 队列前面的元素一定小于等于后面的元素到达源点的距离
 * bfs中队列具有两段性,单调性,
 * 以上双端队列的方式仍然具有两段性,和单调性
 * 则正确
 * 有边权为0/1的边,有可能每条边加入队列多次
 * 比如di=dj di+1>dj+0
 * 队列后面的边权可能更小
 * 由于只能走对角线,每个点的横纵坐标都会变1
 * 奇点就是横纵坐标是奇数的点,同理偶点
 * 则要求终点是偶点
 * 起点和终点奇偶性相同才可以到达
 * 起点(0,0)自然是偶点
 */
public class 电路维修 {
    static class node {
        int x, y;

        public node(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        while (t-- != 0) {
            n = sc.nextInt();
            m = sc.nextInt();
            for (int i = 0; i < n; i++) {
                g[i] = sc.next().toCharArray();
            }
            if (((n + m) & 1) == 1) System.out.println("NO SOLUTION");
            else {
                bfs(0, 0);
                System.out.println(dist[n][m]);
            }
        }
    }

    private static int bfs(int x, int y) {
        q.clear();
        int t = Integer.MAX_VALUE / 2;
        for (int i = 0; i < dist.length; i++) {
            Arrays.fill(dist[i], t);
        }
        for (int i = 0; i < vis.length; i++) {
            Arrays.fill(vis[i], false);
        }
        q.add(new node(x, y));
        dist[x][y] = 0;
        while (!q.isEmpty()) {
            node e = q.poll();
            if (vis[e.x][e.y]) continue;
            vis[e.x][e.y] = true;
            for (int i = 0; i < 4; i++) {
                int nx = e.x + dir[i][0], ny = e.y + dir[i][1];
                if (nx < 0 || nx > n || ny < 0 || ny > m) continue;
                int ex = e.x + idx[i][0], ey = e.y + idx[i][1];
                int d = dist[e.x][e.y] + (g[ex][ey] != op.charAt(i) ? 1 : 0);
                if (d < dist[nx][ny]) {
                    dist[nx][ny] = d;
                    if (g[ex][ey] == op.charAt(i)) q.addFirst(new node(nx, ny));
                    else q.addLast(new node(nx, ny));
                }
            }
        }
        return 0;
    }

    static String op = "\\/\\/";
    static int[][] dir = {{-1, -1}, {-1, 1}, {1, 1}, {1, -1}};
    static int[][] idx = {{-1, -1}, {-1, 0}, {0, 0}, {0, -1}};

    static ArrayDeque<node> q = new ArrayDeque<node>();
    static int n, m, N = 510, M = N * N;
    static int[][] dist = new int[N][N];
    static char[][] g = new char[N][N];
    static boolean[][] vis = new boolean[N][N];
}