售货员的难题

Description

某乡有n个村庄(1< n < 20),有一个售货员,他要到各个村庄去售货,各村庄之间的路程s(0 < s < 1000)是已知的,且A村到B村与B村到A村的路大多不同。为了提高效率,他从商店出发到每个村庄一次,然后返回商店所在的村,假设商店所在的村庄为 1,他不知道选择什么样的路线才能使所走的路程最短。请你帮他选择一条最短的路。

Input

村庄数n和各村之间的路程(均是整数)。

Output

最短的路程

Sample Input

3 {村庄数}

0 2 1 {村庄1到各村的路程}

1 0 2 {村庄2到各村的路程}

2 1 0 {村庄3到各村的路程}

Sample Output

3

思路:如今有很多关于解TSP问题的算法,研究了几天,废寝忘食,发现TSP问题真的好难,主要是理解起来很容易,实现却很困难,时间复杂度为阶乘。

常用的也是易懂的,最简单的就是回溯法,其他还有分支限界法,NP完全性理论,近似算法(费用函数具有三角不等式性质时,可设计一个近似算法,而对于一般情况下的旅行商问题则不可能设计出具有常数性能比的近似算法,除非P=NP,略),网上还有一些其他的算法,我个人比较推荐模拟退火。

下面贴出最简单的回溯法

 1 #include <iostream>
 2 using namespace std;
 3
 4 #define MAX_VALUE 0xFFFFFF
 5 int n;//定点数
 6 int x[25];//当前解
 7 int bestx[25];//当前最优解
 8 int bestc;//当前最优值
 9 int cc;//当前费用
10 int a[25][25];//图的邻接矩阵
11
12 void swap(int &a,int &b)
13 {
14     int tep = a;
15     a=b;
16     b=tep;
17 }
18
19
20 void backtrack(int i)
21 {
22     int j;
23     if(i==n)
24     {
25         if(a[x[n-1]][x[n]]<MAX_VALUE&&a[x[n]][1]<MAX_VALUE&&(bestc==MAX_VALUE||cc+a[x[n-1]][x[n]]+a[x[n]][1]<bestc))
26         {
27             for(j=1;j<=n;j++)
28                 bestx[j]=x[j];
29             bestc=cc+a[x[n-1]][x[n]]+a[x[n]][1];
30         }
31     }
32     else
33     {
34         for(j=i;j<=n;j++)
35             //是否可进入x[j]的子树?
36             if(a[x[i-1]][x[j]]<MAX_VALUE&&(bestc==MAX_VALUE||cc+a[x[i-1]][x[j]]<bestc))
37             {
38                 //搜索子树
39                 swap(x[i],x[j]);
40                 cc+=a[x[i-1]][x[i]];
41                 backtrack(i+1);
42                 cc-=a[x[i-1]][x[i]];
43                 swap(x[i],x[j]);
44             }
45     }

46 }
47
48 int tsp()
49 {
50     int i;
51     for(i=1;i<=n;i++)
52         x[i]=i;
53     bestc = MAX_VALUE;
54
55     cc=0;
56     //搜索x[2:n]的全排列
57     backtrack(2);
58     return bestc;
59 }
60
61 int main()
62 {
63     int i,j,min;
64     cin>>n;
65     for(i=1;i<=n;i++)
66     {
67         for(j=1;j<=n;j++)
68             cin>>a[i][j];
69     }
70     min = tsp();
71     cout<<min<<endl;
72     return 0;
73 }

以下贴出模拟退火的代码【转自  模拟退火算法——解决售货员的难题

 1 /*模拟退火*/
 2 /*AC代码:0ms*/
 3 #include <iostream>
 4 #include <ctime>
 5 #include <cstdlib>
 6 using namespace std;
 7 const int MAX=41;
 8 const int RANN=1000;
 9 const int RUNN=50;
10 const int INF=99999999;
11 int map[MAX][MAX],rpath[RANN][MAX],min[RANN],N;
12 void adjust(int x[],int rn)//rn为调整次数
13 {
14     int a,b;
15     while(rn--)
16     {
17         a=rand()%(N-1)+1;//调整的位置
18         b=rand()%(N-1)+1;
19         swap(x[a],x[b]);
20     }
21 }
22 void get_map()
23 {
24     int i,j;
25     for(i=1;i<=N;i++)
26         for(j=1;j<=N;j++)
27             scanf("%d",&map[i][j]);
28 }
29 void get_rpath()//产生RANN组初始数列
30 {
31     int i,j;
32     for(i=0;i<RANN;i++)
33     {
34         for(j=1;j<=N-1;j++)
35             rpath[i][j]=j+1;
36         adjust(rpath[i],N-1);//初始调整
37         min[i]=INF;
38     }
39 }
40
41 void swap(int &x,int &y)//交换x,y
42 {
43     int t=x;
44     x=y;
45     y=t;
46 }
47 int get_dis(int x[])//返回路径长度
48 {
49     int sum=0,i,p=1;
50     for(i=1;i<=N-1;i++)
51     {
52         sum+=map[p][x[i]];
53         p=x[i];
54     }
55     sum+=map[p][1];
56     return sum;
57 }
58 void numcpy(int x[],int y[])
59 {
60     for(int i=1;i<=N-1;i++)
61         x[i]=y[i];
62 }
63 void get_ans()
64 {
65     int i,j,t=N-1,temp,p[41];
66     while(t--)//调整的范围递减
67     {
68         for(i=0;i<RANN;i++)//遍历RanN组数据
69         {
70             for(j=0;j<RUNN;j++)//对于每组做RunN次
71             {
72                 numcpy(p,rpath[i]);//因为每次都在原有的rpath[i]上改变
73                 adjust(p,t);
74                 temp=get_dis(p);
75                 if(temp<min[i])
76                 {
77                     numcpy(rpath[i],p);//更新rpath[i];
78                     min[i]=temp;
79                 }
80             }
81         }
82     }
83     int ans=min[0];
84     for(i=1;i<RANN;i++)
85         if(min[i]<ans)
86             ans=min[i];
87         printf("%d\n",ans);
88 }
89 int main ()
90 {
91     srand(time(0));//以时间为随机数种子产生随机数
92     while(scanf("%d",&N)!=EOF)
93     {
94         get_map();
95         get_rpath();
96         get_ans();
97     }
98     return 0;
99 }
时间: 2024-10-13 16:21:46

售货员的难题的相关文章

codevs2596 售货员的难题(状压dp)

2596 售货员的难题 时间限制: 1 s 空间限制: 32000 KB 题目等级 : 钻石 Diamond 题目描述 Description 某乡有n个村庄(1<n<=15),有一个售货员,他要到各个村庄去售货,各村庄之间的路程s(0<s<1000)是已知的,且A村到B村与B村到A村的路大多不同.为了提高效率,他从商店出发到每个村庄一次,然后返回商店所在的村,假设商店所在的村庄为1,他不知道选择什么样的路线才能使所走的路程最短.请你帮他选择一条最短的路. 输入描述 Input D

2596 售货员的难题 水深搜

2596 售货员的难题 时间限制: 1 s 空间限制: 32000 KB 题目等级 : 钻石 Diamond 题目描述 Description 某乡有n个村庄(1<n<=15),有一个售货员,他要到各个村庄去售货,各村庄之间的路程s(0<s<1000)是已知的,且A村到B村与B村到A村的路大多不同.为了提高效率,他从商店出发到每个村庄一次,然后返回商店所在的村,假设商店所在的村庄为1,他不知道选择什么样的路线才能使所走的路程最短.请你帮他选择一条最短的路. 输入描述 Input D

2596 售货员的难题

2596 售货员的难题 时间限制: 1 s 空间限制: 32000 KB 题目等级 : 钻石 Diamond 题解 题目描述 Description 某乡有n个村庄(1<n<=15),有一个售货员,他要到各个村庄去售货,各村庄之间的路程s(0<s<1000)是已知的,且A村到B村与B村到A村的路大多不同.为了提高效率,他从商店出发到每个村庄一次,然后返回商店所在的村,假设商店所在的村庄为1,他不知道选择什么样的路线才能使所走的路程最短.请你帮他选择一条最短的路. 输入描述 Inpu

状压DP [SWUST OJ 411] 售货员的难题

售货员的难题(0411) Time limit(ms): 5000 Memory limit(kb): 65535 Submission: 1744 Accepted: 200 Description 某乡有n个村庄(1< n < 20),有一个售货员,他要到各个村庄去售货,各村庄之间的路程s(0 < s < 1000)是已知的,且A村到B村与B村到A村的路大多不同.为了提高效率,他从商店出发到每个村庄一次,然后返回商店所在的村,假设商店所在的村庄为 1,他不知道选择什么样的路线才

P1171 售货员的难题 - 状压DP【最短Hamilton路径】

P1171 售货员的难题 Sol: 最短Hamilton路径,经典的NPC问题,小数据可以通过状压DP 实现. 状态:\(f[i][j]\)表示当前在第i号点,且已经过的点的状态为j 时的最短Hamilton路径. 阶段:若以点为阶段,由于会从点i转移到点i+1,还可能从i+1转移到i-1,不具有无后效性,因此我们考虑以二进制状态为阶段进行转移. 决策:考虑由哪一个点转移而来. 转移:\(f[i][j]=\max \limits_{i\&(1<<i)\&\&i\&

售货员的难题(codevs 2596)

题目描述 Description 某乡有n个村庄(1<n<=15),有一个售货员,他要到各个村庄去售货,各村庄之间的路程s(0<s<1000)是已知的,且A村到B村与B村到A村的路大多不同.为了提高效率,他从商店出发到每个村庄一次,然后返回商店所在的村,假设商店所在的村庄为1,他不知道选择什么样的路线才能使所走的路程最短.请你帮他选择一条最短的路. 输入描述 Input Description 村庄数n和各村之间的路程(均是整数) 输出描述 Output Description 最

codevs 2596 售货员的难题

题目描述 Description 某乡有n个村庄(1<n<=15),有一个售货员,他要到各个村庄去售货,各村庄之间的路程s(0<s<1000)是已知的,且A村到B村与B村到A村的路大多不同.为了提高效率,他从商店出发到每个村庄一次,然后返回商店所在的村,假设商店所在的村庄为1,他不知道选择什么样的路线才能使所走的路程最短.请你帮他选择一条最短的路. 输入描述 Input Description 村庄数n和各村之间的路程(均是整数) 输出描述 Output Description 最

P1171 售货员的难题 喻队状压 DP

题目描述 某乡有n个村庄(1<n<20),有一个售货员,他要到各个村庄去售货,各村庄之间的路程s(0<s<1000)是已知的,且A村到B村与B村到A村的路大多不同.为了提高效率,他从商店出发到每个村庄一次,然后返回商店所在的村,假设商店所在的村庄为1,他不知道选择什么样的路线才能使所走的路程最短.请你帮他选择一条最短的路. 输入输出格式 输入格式: 村庄数n和各村之间的路程(均是整数). 输出格式: 最短的路程. 输入输出样例 输入样例#1: 3 0 2 1 1 0 2 2 1 0

P1171 售货员的难题--搜索(剪枝)

题目背景 数据有更改 题目描述 某乡有nn个村庄(1<n \le 201<n≤20),有一个售货员,他要到各个村庄去售货,各村庄之间的路程s(0<s<1000)s(0<s<1000)是已知的,且AA村到BB村与BB村到AA村的路大多不同.为了提高效率,他从商店出发到每个村庄一次,然后返回商店所在的村,假设商店所在的村庄为11,他不知道选择什么样的路线才能使所走的路程最短.请你帮他选择一条最短的路. 输入输出格式 输入格式: 村庄数nn和各村之间的路程(均是整数). 输出