【Lintcode】816. Traveling Salesman Problem

题目地址:

https://www.lintcode.com/problem/traveling-salesman-problem/description

旅行商问题,给定一个有权无向图,顶点 1 ∼ n 1\sim n 1n,问从顶点 1 1 1出发,走遍所有顶点的花费最小是多少。题目不保证没有平行边。

思路是DFS + 剪枝。首先题目不保证没有平行边,建图的时候要注意,两个顶点的距离,如果有多条边的话,就按小的来算就好。此外,如果发现当前的cost已经大于等于了之前算出来过的某个cost,就直接剪枝返回。代码如下:

import java.util.Arrays;

public class Solution {
    
    private int res = Integer.MAX_VALUE;
    
    /**
     * @param n:     an integer,denote the number of cities
     * @param roads: a list of three-tuples,denote the road between cities
     * @return: return the minimum cost to travel all cities
     */
    public int minCost(int n, int[][] roads) {
        // Write your code here
        // 用邻接矩阵建图
        int[][] graph = new int[n][n];
        for (int[] row : graph) {
            Arrays.fill(row, Integer.MAX_VALUE);
        }
        
        // 注意是无向图,所以要建双向边,并且如果之前已经建过边了,新边来的时候要取小的
        for (int[] road : roads) {
            int len = graph[road[0] - 1][road[1] - 1], minLen = Math.min(len, road[2]);
            graph[road[0] - 1][road[1] - 1] = graph[road[1] - 1][road[0] - 1] = minLen;
        }
        
        dfs(0, 0, 1, graph, new boolean[n]);
        return res;
    }
    
    // cur是当前的出发点,cost是已经产生的耗费,n是已经访问过的顶点数
    private void dfs(int cur, int cost, int n, int[][] graph, boolean[] visited) {
    	// 如果已经访问了所有顶点,则更新答案并返回
        if (n == graph.length) {
            res = Math.min(res, cost);
            return;
        }
        // 如果当前的花费已经大于了之前求过的某个答案,直接返回,不可能是最优解
        if (cost >= res) {
            return;
        }
        
        // 标记当前顶点为已经访问
        visited[cur] = true;
        // 遍历其未访问的邻居,进行访问。新的cost和n要传进去
        for (int i = 0; i < graph[cur].length; i++) {
            if (graph[cur][i] != Integer.MAX_VALUE && !visited[i]) {
                dfs(i, cost + graph[cur][i], n + 1, graph, visited);
            }
        }
        // 回溯的时候恢复现场
        visited[cur] = false;
    }
}

时间复杂度 O ( V + E ) O(V+E) O(V+E),空间 O ( V ) O(V) O(V)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值