POJ旅行商问题——解题报告

旅行商问题

总时间限制: 1000ms 内存限制: 65536kBc++

描述

某国家有n(1<=n<=10)座城市,给定任意两座城市间距离(不超过1000的非负整数)。一个旅行商人但愿访问每座城市刚好一次(出发地任选,且最终无需返回出发地)。求最短的路径长度。spa

输入

第一行输入一个整数n
接下来n行,每行n个数,用空格隔开,以邻接矩阵形式给出城市间距离。该邻接矩阵是对称的,且对角线上全为0code

输出

一行,最短路径的长度排序

样例输入
6
0 16 1 10 12 15
16 0 10 2 10 8
1 10 0 10 5 10
10 2 10 0 9 3
12 10 5 9 0 8
15 8 10 3 8 0
样例输出
19

解题思路

这个问题能够抽象为在\(n\)阶无向彻底图\(K_n\)中,给定每一个边加权(长度),而后在该带权图中求一条权和最小的哈密顿通路(只求解最小权和便可)。个人想法是使用深度优先搜索求解,过程当中使用了set来储存通路的长度,因为set使用二叉搜索树,能够在\(O(\log n)\)时间内完成元素插入,同时自动对元素排序,而且可以在\(O(1)\)时间内得到集合的最大和最小值,以略微节省运算时间。另外使用stack容器来临时储存全局变量sum(长度和)的值。递归

代码
#include <bits/stdc++.h>
using namespace std;
int cities[12][12] = {};
bool visited[12] = {};
//标记去过的城市,若是去过了,则记true
int n;
int sum;
set<int> path;
stack<int> temp;
void dfs(int start)
{
    bool flag = true;
    for (int i = 1; i <= n; i++)
        if (!visited[i])
            flag = false;
    if (flag)
    {
        path.insert(sum);
        return;
    }
    //设置边界
    //若是没到递归边界,继续
    for (int i = 1; i <= n; i++)
    {
        if (visited[i] == false)
        {
            visited[i] = true;
            if (sum > *path.begin() && path.size() != 0)
            {
                visited[i] = false;
                continue;
            }
            temp.push(sum);
            sum += cities[start][i];
            dfs(i);
            sum = temp.top();
            temp.pop();
            visited[i] = false;
        }
    }
}

int main()
{
    scanf("%d", &n);
    sum = 0;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            scanf("%d", &cities[i][j]);
    for (int i = 1; i <= n; i++)
        dfs(i);
    printf("%d\n", *path.begin());
    return 0;
}
其余想法

因为此题中旅行商能够从任意城市出发,我在解题的过程当中分别搜索了\(n\)个不一样起点的解。但能够看出,搜索的不一样路径中有大量重和部分,虽然对那些不可能成为最优解的路径进行了剪枝,搜索的效率仍然不高。
因而便有了另一种思路,即,在图中先搜索出一条最短的哈密顿回路,而后删去这条回路中的最长边,便获得一条哈密顿通路。由最短的哈密顿回路获得的这条哈密顿通路是不是最短的哈密顿回路,我并无进行严格的证实。内存

相关文章
相关标签/搜索