毕业旅行问题

毕业旅行问题

思路

首先容易想到的思路就是进行深度优先遍历,将所有可能的结果算出来求其最小值。但是这种算法明显时间复杂度过大,不在考虑范围内。
对于这种求最值的问题,我们一般想到用动态规划的方式求解。动态规划是将一个大的问题分解成几个小的问题。我们需要确定我们的dp数组所代表的含义,并找出递推公式。
对于这道题我们所要求的是从0号城市出发(即北京)经过其他所有城市(集合P)最终又回到0号城市的最小费用M;显然M等于Min{P中的一个城市City经过P-{City}城市最终又回到0号城市的最小费用+0号城市到City城市的费用}。于是我们可以定义dp[i][P] = Min{dp[j][P-j]+D}。其中P是城市集合。
我们该如何表示该集合,我们可以利用状态压缩的想法。将每一个城市作为一个二进制数的一位,一个int型数最多可以表示32个city.满足该题的最多20个城市。
dp[i][0]代表从i城市出发不经过其他城市直接到0号城市。其值为dp[i][0] = matrix[i][0]
我们最终的答案为dp[0][P]。其中P包含了除0号城市以外其他所有的城市。由上面所述,我们可以根据大集合的值是由小集合决定的。故第一层循环为循环所有的集合数。然后便是选取起点,再之后循环下一城市即可。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

public class Main {
        public static void main(String[] args) {
                Scanner scanner = new Scanner(System.in);
                int n  = scanner.nextInt();
                scanner.nextLine();
                int[][] matrix = new int[n][n];
                for(int i = 0 ; i < n; i++){
                        for(int j  = 0; j < n; j++){
                                matrix[i][j] = scanner.nextInt();
                        }
                        scanner.nextLine();
                }
                int[][] dp = new int[n][1<<(n-1)];
                for(int i = 0 ; i < n;i++){
                        dp[i][0] = matrix[i][0];
                }
                //0不包含在dp数组第二维中,故i<1<<n-1
                for(int i =1 ; i <(1<<(n-1));i++){
                        //选取起点
                        for(int j =0 ; j < n ;j++){
                                dp[j][i] = Integer.MAX_VALUE>>1;
                              if(check(i,j))
                                      continue;
                              for(int k = 1 ;k<n;k++){
                                      if(check(i,k)){
                                              int tem = unmask(i,k);
                                              dp[j][i] = Math.min(dp[j][i],dp[k][tem]+matrix[j][k]);
                                      }
                              }
                        }
                }
                System.out.println(dp[0][(1<<(n-1))-1]);

        }
        public static boolean check(int a, int b){
                if(b==0){
                        return false;
                }
                //如果等于0说明b不包含在a中。
                return (a&(1<<(b-1)))!=0;
        }
        public static int unmask(int a,int b){
                return  a&(~(1<<(b-1)));
        }
}
全部评论

相关推荐

下北泽:都是校友,还是同届,我就说直白点,不委婉了,我相信你应该也不是个玻璃心,首先你觉得一个双非的绩点写简历上有用吗?班长职务有用吗?ccf有用吗?企业会关心你高数满分与否吗?第二,第一个项目实在太烂,一眼就能看出是外卖,还是毫无包装的外卖,使用JWT来鉴权,把热点数据放进Redis这两个点居然还能写进简历里,说难听点这两个东西都是学个几十分钟,调用个API就能完成的事情,在双非一本的条件下,这种项目你觉得能拿出手吗,第二个项目你写的东西和你的求职方向有任何的匹配吗?第三,计设那一块毫无价值,如果想突出自己会前端,直接写入专业技能不行吗,最后,专业技能里像深入理解JVM底层原理这种你觉得这句话你自己真的能匹配吗?都是校友加上同届,我措辞直接,但希望能点出你的问题,想进大厂还得继续沉淀项目和学习
点赞 评论 收藏
分享
03-07 17:34
吉林大学 Java
野猪不是猪🐗:说说我的看法: 1. 分布式微服务不是必学的,先把mysql redis spring生态 juc jvm os 计网这些学的差不多,就能应对大部分常规八股。项目直接用单体项目也是可以的 2. 你的学历有优势,后续把外卖做个拓展换皮(或者去吃透一个不那么烂大街的项目),就能够收获不少面试。但重心建议放在八股算法上,项目不必追求高级或独特,但必须吃透,并且要提前准备一些话术,比如技术选型,为什么考虑用a而不是用b 3. 五六月份大厂暑期的难度会下降(因为大佬都选好offer开始释放了,很多甚至都入职了),所以心态要稳住,不要陷入内耗 加油
投递字节跳动等公司9个岗位
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务