格子里的整数-贪心算法

Description
Given a square grid of size n, each cell of which contains integer cost which represents a cost to traverse through that cell, we need to find a path from top left cell to bottom right cell by which total cost incurred is minimum.
Note : It is assumed that negative cost cycles do not exist in input matrix.
Input
The first line of input will contain number of test cases T. Then T test cases follow . Each test case contains 2 lines. The first line of each test case contains an integer n denoting the size of the grid. Next line of each test contains a single line containing N*N space separated integers depecting cost of respective cell from (0,0) to (n,n).
Constraints:1<=T<=50,1<= n<= 50
Output
For each test case output a single integer depecting the minimum cost to reach the destination.
Sample Input 1 
2 5 31 100 65 12 18 10 13 47 157 6 100 113 174 11 33 88 124 41 20 140 99 32 111 41 20 2 42 93 7 14
Sample Output 1
327 63
 
解题思路:
看到题目开始以为是动态规划,用递推求出。但细看发现点的移动方向不固定,可以朝任意方向移动。发现题目给定矩阵也可以转换成图,题目其实是单端最短路径的一种变体。
这里需要将输入的矩阵转换一下,转换成邻接矩阵,不相邻的点距离设置为最大。
得到邻接矩阵后,剩下的就是用dijkstra方法求最短路径。
这里顺带说下dijkstra,其把图中顶点集合V分成两组,第一组为已求出最短路径的顶点集合(用S表示,初始时S中只有一个源点,以后每求得一条最短路径 , 就将加入到集合S中,直到全部顶点都加入到S中),第二组为其余未确定最短路径的顶点集合(用U表示),按最短路径长度的递增次序依次把第二组的顶点加入S中。每次将一个点加入S后,更新U中所有点的最短路径。
算法需要的数据结构:
visited[] 为false表示在集合U中,为true表示在集合S中。
dis[] ,dis[i]表示第i个点距离初始点的最短距离,不相邻的点初始值为无穷大。
acc[][], 邻接矩阵,arr[i][j]表示第i个点与第j个点的最短距离,不相邻的点初始值为无穷大。
 
算法步骤:
1.首先初始化arr[][]和dis[],将初始点加入S,visited[0]置为true;
2.将U中dis[i]最小的点p加入到S中。
3.遍历U中所有的点,如果存在某一个点q,使得dis[p][q] + dis[p] < dis[q],则更新dis[q];
4.重新返回步骤2,直到所有的点都已经加入到集合S。
 
实现代码如下:
 1 import java.util.*;
 2 
 3 public class Main { // 注意类名必须为Main
 4     public static int max = 1000000;
 5     public static void main(String[] args) {
 6         Scanner scan = new Scanner(System.in);
 7         int number = scan.nextInt();
 8         scan.nextLine();
 9         // number个测试样例
10         for (int k = 0; k < number; k++){
11             // 输入数据
12             int n = scan.nextInt();
13             int[][] arr = new int[n][n];
14             for (int i = 0; i < n; i++) {
15                 for (int j = 0; j < n; j++) {
16                     arr[i][j] = scan.nextInt();
17                 }
18             }
19             // 初始化acc[][]
20             int size = n*n;
21             int[][] acc = new int[size][size];
22             for (int i = 0; i < size; i++)
23                 for (int j = 0; j < size; j++)
24                     acc[i][j] = max;
25             int[][] temp = {{-1,0},{1,0},{0,-1},{0,1}};
26             for (int i = 0; i < n; i++)
27                 for (int j = 0; j < n; j++) {
28                     // 点arr[i]本身赋值
29                     int index = transform(i, j, n);
30                     acc[index][index] = arr[i][j];
31                     // 点arr[i]相邻的点赋值
32                     for (int q = 0; q < temp.length; q++) {
33                         int X = i+temp[q][0];
34                         int Y = j+temp[q][1];
35                         if (X >=0 && X < n && Y >= 0 && Y < n) {
36                             acc[transform(X,Y,n)][index] = arr[i][j];
37                         }
38                     }
39                 }
40             // 获得结果
41             int[] dis = dijkstra(acc);
42             System.out.println(arr[0][0]+dis[size-1]);
43         }
44     }
45     // 将i,j转为index
46     public static int transform(int i, int j, int n) {
47         return i*n+j;
48     }
49     // 根据顶点的邻接矩阵,使用djikstra算法计算出初始点到各个点的最短路径
50     public static int[] dijkstra(int[][] acc) {
51         // 初始化dis[]
52         int size = acc.length;
53         int[] dis = new int[size];
54         for (int i = 0; i < size; i++)
55             dis[i] = acc[0][i];
56         boolean[] visited = new boolean[size];
57         visited[0] = true;
58         // 执行size-1次操作,可以找到所有点的最短路径值
59         for (int i = 1; i < size; i++) {
60             // 找到集合V中dis[i]最小的点p
61             int min = max;
62             int p = -1;
63             for (int j = 0; j < size; j++) {
64                 if (!visited[j] && dis[j] < min) {
65                     p = j;
66                     min = dis[j];
67                 }
68             }
69             // 将点p加入到集合S中
70             visited[p] = true;
71             // 更新所有集合V中的点q,dis[q] = Math.min(dis[q], dis[p]+acc[p][q])
72             for (int q = 0; q < size; q++) {
73                 if (!visited[q] && (dis[p] + acc[p][q] < dis[q])) {
74                     dis[q] = dis[p] + acc[p][q];
75                     // 如果更新到了终点,直接返回结果,不用再执行后续更新
76                     if (q == size-1)
77                         return dis;
78                 }
79             }
80         }
81         // 返回结果
82         return dis;
83     }
84 }

 

posted @ 2021-04-08 00:40  凝冰物语  阅读(93)  评论(0编辑  收藏  举报