- 2022-06-20:一个二维矩阵,上面只有 0 和 1,只能上下左右移动,
 如果移动前后的元素值相同,则耗费 1 ,否则耗费 2。
 问从左上到右下的最小耗费。
 来自网易。3.27笔试。
建立模型:
/**
     * 求解花费的最小代价
     * 建模:dijskra模型来使用
     * 步骤:a.初始时,s只包含源点,即s={v},v的距离为0,U包含除v外的其他顶点,即:U={其余顶点},若v与U中顶点有边,则<u,v>正常有权值,若u不是v的出边邻接点,则<u,v>权值为无穷大。
     * b.从U中选取一个距离v最小的顶点k,把k,加入S中(该选定的距离就是v到k的最短路径长度)
     * c.以k为新考虑的中间点,修改U中个顶点的距离;若从源点v到顶点u的距离(经过k)比原来距离(不经过k)短,则修改顶点u的距离值,修改后的距离值的顶点k的距离加上边上的权
     * d.重复步骤b和c直到所有顶点都包含在s中。
     *
     * 这个模型是可以求解最短距离问题,最少开销问题,
     *
     * @param map
     * @return
     */
    public static int bestWalk(int[][] map) {
        int n = map.length;
        int m = map[0].length;
        //小根堆:【代价,行,列】
        //根据代价,谁代价小,谁放在堆的上面
        PriorityQueue<int[]> heap = new PriorityQueue<>((a, b) -> a[0] - b[0]);
        //poped[i][j] == true 已经弹出过了!不要再处理,直接忽略
        //poped[i][j] == false 之间(i,j)没弹出过!要处理
        boolean[][] poped = new boolean[n][m];
        heap.add(new int[]{0, 0, 0});
        int ans = 0;
        while (!heap.isEmpty()) {
            //当前弹出,【代价,行,列】,当前位置
            //当前弹出的是各个方向中最小代价的
            int[] cur = heap.poll();
            int dis = cur[0];
            int row = cur[1];
            int col = cur[2];
            if (poped[row][col]) {
                continue;
            }
            //第一次弹出
            poped[row][col] = true;
            //到达最终的端点
            if (row == n - 1 && col == m - 1) {
                ans = dis;
                break;
            }
            add(dis, row - 1, col, map[row][col], n, m, map, poped, heap);
            add(dis, row + 1, col, map[row][col], n, m, map, poped, heap);
            add(dis, row, col - 1, map[row][col], n, m, map, poped, heap);
            add(dis, row, col + 1, map[row][col], n, m, map, poped, heap);
        }
        return ans;
    }
    /**
     * @param preDistance 之前的距离
     * @param row         当前要加入的是什么位置
     * @param col
     * @param preValue    前一个格子是什么值
     * @param n           边界
     * @param m
     * @param map         每一个格子的值,都在map里
     * @param poped       当前位置如果是弹出过的位置,要忽略
     * @param heap        小根堆
     */
    public static void add(int preDistance, int row, int col, int preValue, int n, int m, int[][] map, boolean[][] poped, PriorityQueue<int[]> heap) {
           if (row>=0 && row<n && col>=0 && col<m && !poped[row][col]){
               heap.add(new int[]{preDistance+(map[row][col] == preValue ?1:2),row,col});
           }
    }
 /**
     * 新建模型:求解多个满足条件下面,最好的城市编号
     * 模型:Floyd模型
     *
     * @param n                 n个城市
     * @param edges             城市之间的开销
     * @param distanceThreshold 一定的金额
     * @return 最好的方案
     */
    public int findTheCity(int n, int[][] edges, int distanceThreshold) {
        int dist[][] = new int[n][n];//存储距离
        //初始化
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                dist[i][j] = 1000000;
            }
            dist[i][i] = 0;
        }
        //再赋值
        for (int arr[] : edges) {
            dist[arr[0]][arr[1]] = arr[2];
            dist[arr[1]][arr[0]] = arr[2];
        }
        //计算
        for (int k = 0; k < n; k++) {
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    dist[i][j] = Math.min(dist[i][j], dist[i][k] + dist[k][j]);
                }
            }
        }
        int min = Integer.MAX_VALUE;
        int minIndex = 0;
        int pathNum[] = new int[n];//存储距离
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (dist[i][j] <= distanceThreshold) {
                    pathNum[i]++;
                }
            }
            if (pathNum[i] <= min) {
                min = pathNum[i];
                minIndex = i;
            }
        }
        return minIndex;
    }