ACM解题总结——HihoCoder1200 (微软笔试题)

来源:互联网 发布:视频打马赛克软件 编辑:程序博客网 时间:2024/05/02 05:04

(p.s: 初次尝试用Java做题,感觉还不错。。。 )


题目来源:
    HihoCoder1200 

题目要求:
    
Little Ho is playing a role-playing game. There are N cities in the game which are numbered from 1 to N. Every time Little Ho moves to another city his charisma (a kind of character attribute) will increase by 1 point no matter whether the city is visited before. For example if Little Ho’s moving path is 1->2->3->2->3->1 his charisma will increase by 5.
Little Ho wants to maximize his charisma. However moving between cities costs action points. More precisely moving from city i to city j costs him Aij action points. Little Ho wants to know how many points of charisma he can get by using no more than M action points? He may start at any city.

题目大意:
    题目的要求很简单:给定一个有向图。初始情况下,位于点1。要求在给定最长的移动距离的情况下,计算可以经过的最多的点的个数,点可以重复经过。

解答:
    本题其实考查了一个知识点,就是图的邻接矩阵表示方式的应用。基本的解题思路是:逐渐增加经过的点数,同时查看总的路程是否超出给定的上限,逐渐逼近至最优解即可。以下时具体的解答思路:

·数据结构:
    对于本题,我们采用邻接矩阵对图进行存储。邻接矩阵是一个N×N的矩阵A,其中N为图中点的个数,如果图中从点ij存在长度为k的有向边,那么矩阵元素A[i][j] = k。由于从任意点到它自身是没有边的,因此,这里约定A[i][i] = +∞。下图是一个邻接矩阵表示图的例子:
 
    对于邻接矩阵中的每一个元素A[i][j],我们有另外一种解释方式,即从点i到点j,中间经过0个点的前提下的最短距离。 接下来,我们可以采用一种类似于矩阵相乘的思路,来计算出任意两点间,在中间经过1个点的前提下的最短距离。
    基本思路为:对于点i到点j中间经过1个点的距离,可以枚举每一个节点k作为中间经过的点,此时,ij的距离为ik的距离加kj的距离,因此:记点i到点j经过中间经过一个点的最短距离为A1[i][j],则:
    
选取不同的k点,求得点i到点j的最短距离,因此A1[i][j]的最终计算方法是:

计算所有的A1[i][j],就可以得到新的矩阵A1,该矩阵存储了任意两点间在经过一个中间点的前提下的最短距离。对于上面的样例,A1矩阵计算结果如下:

    对于中间经过2个点、3个点 ...... n个点的情况的处理也是类似的,将对应的矩阵分别记为A2,A3,... An,这里可以得到更一般的结论:
     
    这里的乘法不是传统意义上的矩阵相乘,结果矩阵中的每一个元素的值利用上面的公式得出。做一次上面的计算所需的时间是O(N³)
    此时,我们得到了一个解答本题的基本思路:首先根据输入的图得到矩阵A0,并通过A0得到矩阵A1,A2, ... 然后检查A0, A1, A2,... 中的每一个元素,如果矩阵Ak中存在小于约定最大值的元素Ak[i][j],那么说明存在一条从i点经过k个中间点到点j的路径,并且该路径的长度不超过给定的最值。所以,通过遍历找到使得矩阵Ak中至少包含一个小于给定最值的元素的k值后,k+1就是需要求解的答案。

·计算优化:
    上文中给出了求解本题的基本的思路。但是,由A0得到A1的时间复杂度是O(N³),由A1得到A2的时间复杂度同样是O(N³),因此如果遍历M个矩阵,计算矩阵的时间就是O(M×N³),同时,检查每个矩阵元素的时间复杂度是O(N²),因此,总的是间复杂度是O(M×N³)。这样的计算方式效率很低。
    由于图中的边的长度最小为1,因此,对于给定的路程上限M,通过计算矩阵A1,A2,... AM一定可以得到最终的结果,即对于给定的路程上限M,不论采用怎样的策略,经过的点的个数一定不会超过M个。
    这里可以采用快速计算幂的思想,预先计算出A1, A2, A4, ... AlogM,然后,对于任意的矩阵Ai,均可以采用
A1, A2, A4, ... AlogM中的某些项得到。
    然后采用二分的思想,首先考察AlogM是否符合,如果符合,将AlogMAlogM/2合并,检查是否符合,如果符合再合并下一项,如果不符合,则将当前项恢复,继续合并下一项考察。
    当最终遍历至A1时,就得到了符合条件的矩阵Ak对应的最大的k值。此时,计算的复杂度是O(logM×N³),就可以通过了。

输入输出格式:
    输入:
Line 1: N and M, the number of cities and the initial action points.

Line 2~N+1: An N x N matrix A. Aij is the action point cost as described above.

For 30% of the data: 2≤N≤5,1≤M≤50,0≤Aij≤10

For 60% of the data: 2≤N≤50,1≤M≤2000,0≤Aij≤10

For 100% of the data: 2≤N≤100,1≤M≤1,000,000,000,0≤Aij≤20

    输出:

         The maximum points of charisma Little Ho can get.


程序代码:

import java.util.Scanner;/** * This is the ACM problem solving program for hihoCoder 1200. *  * @version 2016-08-13 * @author Zhang Yufei. */public class Main{// Input data.private static int N, M;/** * Define the matrix to record the graph. *  * @author Zhang Yufei */private static class Graph {public int[][] matrix;public Graph(int N) {matrix = new int[N][N];for (int i = 0; i < N; i++) {for (int j = 0; j < N; j++) {matrix[i][j] = -1;}}}}/* * Define the array to store the graph. dist[s].matrix[i][j] means the * minimum distance between node i and node j, given that the path between * those nodes contains s nodes. */private static Graph[] dist;/** * This is the main program. *  * @param args *            command line parameter list. */public static void main(String[] args) {Scanner scan = new Scanner(System.in);N = scan.nextInt();M = scan.nextInt();int count = (int) (Math.log(M) / Math.log(2)) + 1;dist = new Graph[count];for (int i = 0; i < count; i++) {dist[i] = new Graph(N);}for (int i = 0; i < N; i++) {for (int j = 0; j < N; j++) {dist[0].matrix[i][j] = scan.nextInt();if(i == j) {dist[0].matrix[i][j] = -1;}}}scan.close();for (int i = 1; i < count; i++) {compute(dist[i - 1], dist[i - 1], dist[i]);}int ans = 0;Graph temp1 = new Graph(N);Graph temp2 = new Graph(N);int c;for (c = count - 1; c >= 0; c--) {if (check(dist[c])) {for (int i = 0; i < N; i++) {for (int j = 0; j < N; j++) {temp1.matrix[i][j] = dist[c].matrix[i][j];}}ans += (int) Math.pow(2, c);break;}}for (c--; c >= 0; c--) {compute(temp1, dist[c], temp2);if (check(temp2)) {ans += (int) Math.pow(2, c);Graph t = temp1;temp1 = temp2;temp2 = t;}}System.out.println(ans);}/** * This function computes the minimum distance between every pairs of node * in graph from all paths which contains the (m + n) node. *  * @param g1 *            The matrix1 to compute. It records the minimum distance *            between every pairs of node given that the path contains m *            nodes. * @param g2 *            The another matrix to compute.It records the minimum distance *            between every pairs of node given that the path contains n *            nodes. * @param result *            The store space of the result matrix, which contains the *            minimum distance between every pairs of node in graph from all *            paths which contains the (m + n) node. */public static void compute(Graph g1, Graph g2, Graph result) {for (int i = 0; i < N; i++) {for (int j = 0; j < N; j++) {result.matrix[i][j] = -1;for (int k = 0; k < N; k++) {if (g1.matrix[i][k] != -1 && g2.matrix[k][j] != -1) {int t = g1.matrix[i][k] + g2.matrix[k][j];if (result.matrix[i][j] == -1 || result.matrix[i][j] > t) {result.matrix[i][j] = t;}}}}}}/** * This function checks if the matrix is legal. *  * @param g *            The matrix to check. * @return If the matrix is legal, returns <code>true</code> or returns *         <code>false</code> */public static boolean check(Graph g) {for (int i = 0; i < N; i++) {for (int j = 0; j < N; j++) {if (g.matrix[i][j] != -1 && g.matrix[i][j] <= M) {return true;}}}return false;}}


0 0
原创粉丝点击