1267: 旅行商问题

1267: 旅行商问题

时间限制: 1 Sec  内存限制: 128 MB
提交: 53  解决: 6
[提交] [状态] [讨论版] [命题人:外部导入]

题目描述

旅行商问题是这样一个问题:给定一系列城市和每对城市之间的距离,求解访问每一座城市一次并回到起始城市的最短回路。它是组合优化中的一个NP难问题,在运筹学和理论计算机科学中非常重要。

--摘自百度百科      

输入

第一行一个正整数n表示城市数量。(n <= 13)
接下来输入一个n行n列邻接矩阵,第i行j列一个非负整数d表示城市i到j的距离。(d <= 1e7)
保证城市i到j的距离等于城市j到i的距离且到自身距离为0。

输出

输出一个非负整数表示经过每个城市一次且仅一次并回到起点的最短距离。

样例输入 Copy
4
0  5  9  4
5  0  13 2
9  13 0  7
4  2  7  0
样例输出 Copy
23
来源/分类

分支限界法

import java.util.*;
//1267
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt(); // 城市数量
 
        int[][] distance = new int[n][n]; // 邻接矩阵
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                distance[i][j] = scanner.nextInt();
            }
        }
 
        int[][] dp = new int[1 << n][n]; // dp数组,表示从起点出发,经过某些城市,到达城市i的最短距离
        for (int i = 0; i < (1 << n); i++) {
            Arrays.fill(dp[i], Integer.MAX_VALUE / 2); // 初始化为最大值
        }
        dp[1][0] = 0; // 起点到达起点距离为0
 
        // 动态规划求解
        for (int mask = 1; mask < (1 << n); mask++) { // mask表示经过的城市集合的状态
            for (int i = 0; i < n; i++) {
                if (((mask >> i) & 1) == 1) { // 如果城市i在mask中
                    for (int j = 0; j < n; j++) {
                        if (((mask >> j) & 1) == 0) { // 如果城市j不在mask中
                            dp[mask | (1 << j)][j] = Math.min(dp[mask | (1 << j)][j], dp[mask][i] + distance[i][j]);
                        }
                    }
                }
            }
        }
 
        // 找到经过所有城市一次且仅一次并回到起点的最短距离
        int minDistance = Integer.MAX_VALUE;
        for (int i = 0; i < n; i++) {
            minDistance = Math.min(minDistance, dp[(1 << n) - 1][i] + distance[i][0]);
        }
 
        System.out.println(minDistance);
    }
}

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值