动态规划求解TSP(旅行商)问题

某推销员要从城市v1出发,访问其它城市v2v3v6各一次且仅一次,最后返回v1D为各城市间的距离矩阵。问:该推销员应如何选择路线,才能使总的行程最短?

 

1、变量设定

阶段k:已遍历过k个结点,k=1,2…6,7

        K=1表示刚从V1出发,k=7表示已回到起点V1

状态变量Xk=(iSk):已遍历k个结点,当前位于i结点,还未遍历的结点集合为Sk。则X1=(1{2,3,4,5,6})X6=(i,Φ)X7=(1,Φ)

决策变量Uk=(ij):已遍历k个结点,当前位于i结点,下一个结点选择j

状态转移方程:Xk+1 = T(XkUk) = (jSk-{j})

k阶段的指标函数Vk = D[i,j]

最优指标函数Fk(Xk) = Fk(iSk):已遍历k个结点,当前从i结点出发,访问Sk中的结点一次且仅一次,最后返回起点V1的最短距离。

Fk(iSk) = min{ D[i,j] + Fk+1(jSk-{j}) }     1k6

   F7(X7)= F7(1,Φ) = 0

 

2、分析:

 

1k=6时,F6(i,Φ) = min{D[i,1] + F7(X7)} = D[i,1]    i=2,3,4,5,6

 

 

X6=(i,Φ)

U6=(ij)

X7=(1,Φ)

V6=D[i,j]

F7(1,Φ)

V6 + F7(X7)

(2,Φ)

(21)

(1,Φ)

12

0

12=F6(2,Φ)

(3,Φ)

(31)

(1,Φ)

23

0

23=F6(3,Φ)

(4,Φ)

(41)

(1,Φ)

34

0

34=F6(4,Φ)

(5,Φ)

(51)

(1,Φ)

45

0

45=F6(5,Φ)

(6,Φ)

(61)

(1,Φ)

56

0

56=F6(6,Φ)

k=6时,对于每一种状态X6,都有唯一的决策U6

 

2k=5时,F5(iS5) = min{D[i,j] + F6(j,Φ)}     i=2,3,4,5,6

 

X5=(i,S5)

U5=(i,j)

X6=(j, Φ)

V5=D[i,j]

F6(j,Φ)

V5 + F6(X6)

(2,{6}}

(2,6)

(6,Φ)

21

56

77=F5(2,{6})

(2,{5}}

(2,5)

(5,Φ)

25

45

70=F5(2,{5})

(2,{4}}

(2,4)

(4,Φ)

30

34

64=F5(2,{4})

(2,{3}}

(2,3)

(3,Φ)

18

23

41=F5(2,{3})

(3,{6})

(3,6)

(6,Φ)

15

56

71=F5(3,{6})

(3,{5})

(3,5)

(5,Φ)

10

45

55=F5(3,{5})

(3,{4})

(3,4)

(4,Φ)

5

34

39=F5(3,{4})

(3,{2})

(3,2)

(2,Φ)

19

12

31=F5(3,{2})

(4,{6})

(4,6)

(6,Φ)

16

56

72=F5(4,{6})

(4,{5})

(4,5)

(5,Φ)

8

45

53=F5(4,{5})

(4,{3})

(4,3)

(3,Φ)

4

23

27=F5(4,{3})

(4,{2})

(4,2)

(2,Φ)

32

12

44=F5(4,{2})

(5,{6})

(5,6)

(6,Φ)

18

56

74=F5(5,{6})

(5,{4})

(5,4)

(4,Φ)

10

34

44=F5(5,{4})

(5,{3})

(5,3)

(3,Φ)

11

23

34=F5(5,{3})

(5,{2})

(5,2)

(2,Φ)

27

12

39=F5(5,{2})

(6,{5})

(6,5)

(5,Φ)

12

45

57=F5(6,{5})

(6,{4})

(6,4)

(4,Φ)

20

34

54=F5(6,{4})

(6,{3})

(6,3)

(3,Φ)

16

23

39=F5(6,{3})

(6,{2})

(6,2)

(2,Φ)

22

12

34=F5(6,{2})

k=时,对于每一种状态X5,都有唯一决策U5

 

 

 

3k=4时,F4(i,S4) = min(D[i,j] + F5(j,S5) )     i=2,3,4,5,6

 

X4=(i,S4)

U4=(i,j)

X5=(j,S5)

V4=D[i,j]

F5(j,S5)

V4 + F5(j,S5)

(2,{3,4})

(2,3)

(3,{4})

18

39

57=F4(2,{3,4})

(2,4)

(4,{3})

30

27

57=F4(2,{3,4})

(2,{4,5})

(2,4)

(4,{5})

30

53

83

(2,5)

(5,{4})

25

44

69=F4(2,{4,5})

(2,{5,6})

(2,5)

(5,{6})

25

74

99

(2,6)

(6,{5})

21

57

78=F4(2,{5,6})

(2,{3,5})

(2,3)

(3,{5})

18

55

73

(2,5)

(5,{3})

25

34

59=F4(2,{3,5})

(2,{3,6})

(2,3)

(3,{6})

18

71

89

(2,6)

(6,{3})

21

39

60=F4(2,{3,6})

(2,{4,6})

(2,4)

(4,{6})

30

72

102

(2,6)

(6,{4})

21

54

75=F4(2,{4,6})

(3,{2,4})

(3,2)

(2,{4})

19

64

83

(3,4)

(4,{2})

5

44

49=F4(3,{2,4})

(3,{2,5})

(3,2)

(2,{5})

19

70

89

(3,5)

(5,{2})

10

39

49=F4(3,{2,5})

(3,{2,6})

(3,2)

(2,{6})

19

77

96

(3,6)

(6,{2})

15

34

49=F4(3,{2,6})

(3,{4,5})

(3,4)

(4,{5})

5

53

58

(3,5)

(5,{4})

10

44

54=F4(3,{4,5})

(3,{4,6})

(3,4)

(4,{6})

5

72

77

(3,6)

(6,{4})

15

54

69=F4(3,{4,6})

(3,{5,6})

(3,5)

(5,{6})

10

74

84

(3,6)

(6,{5})

15

57

72=F4(3,{5,6})

(4,{2,3})

(4,2)

(2,{3})

32

41

73

(4,3)

(3,{2})

4

31

34=F4(4,{2,3})

(4,{2,5})

(4,2)

(2,{5})

32

70

102

(4,5)

(5,{2})

8

39

47=F4(4,{2,5})

(4,{2,6})

(4,2)

(2,{6})

32

77

109

(4,6)

(6,{2})

16

34

50=F4(4,{2,6})

(4,{3,5})

(4,3)

(3,{5})

4

55

59

(4,5)

(5,{3})

8

34

42=F4(4,{3,5})

(4,{3,6})

(4,3)

(3,{6})

4

71

75

(4,6)

(6,{3})

16

39

55=F4(4,{3,6})

(4,{5,6})

(4,5)

(5,{6})

8

74

82

(4,6)

(6,{5})

16

57

73=F4(4,{5,6})

(5,{2,3})

(5,2)

(2,{3})

27

41

68

(5,3)

(3,{2})

11

31

42=F4(5,{2,3})

(5,{2,4})

(5,2)

(2,{4})

27

64

91

(5,4)

(4,{2})

10

44

54=F4(5,{2,4})

(5,{2,6})

(5,2)

(2,{6})

27

77

104

(5,6)

(6,{2})

18

34

52=F4(5,{2,6})

(5,{3,4})

(5,3)

(3,{4})

11

39

50

(5,4)

(4,{3})

10

27

37=F4(5,{3,4})

(5,{3,6})

(5,3)

(3,{6})

11

71

82

(5,6)

(6,{3})

18

39

57=F4(5,{3,6})

(5,{4,6})

(5,4)

(4,{6})

10

72

82

(5,6)

(6,{4})

18

54

72=F4(5,{4,6})

(6,{2,3})

(6,2)

(2,{3})

22

41

63

(6,3)

(3,{2})

16

31

47=F4(6,{2,3})

(6,{2,4})

(6,2)

(2,{4})

22

64

86

(6,4)

(4,{2})

20

44

64=F4(6,{2,4})

(6,{2,5})

(6,2)

(2,{5})

22

70

92

(6,5)

(5,{2})

12

39

51=F4(6,{2,5})

(6,{3,4})

(6,3)

(3,{4})

16

39

55

(6,4)

(4,{3})

20

27

47=F4(6,{3,4})

(6,{3,5})

(6,3)

(3,{5})

16

55

71

(6,5)

(5,{3})

12

34

46=F4(6,{3,5})

(6,{4,5})

(6,4)

(4,{5})

20

53

73

(6,5)

(5,{4})

12

44

56=F4(6,{4,5})

 

 

4k=3时,F3(i,S3) = min{D[i,j] + F4(j,S4)}   i=2,3,4,5,6

 

X3=(i,S3)

U3=(i,j)

X4=(j,S4)

V3=D[i,j]

F4(j,S4)

V3 + F4(j,S4)

(2,{3,4,5})

(2,3)

(3,{4,5})

18

54

72

(2,4)

(4,{3,5})

30

42

72

(2,5)

(5,{3,4})

25

37

62=F3(2,{3,4,5})

(2,{3,4,6})

(2,3)

(3,{4,6})

18

69

87

(2,4)

(4,{3,6})

30

55

85

(2,6)

(6,{3,4})

21

47

68=F3(2,{3,4,6})

(2,{3,5,6})

(2,3)

(3,{5,6})

18

72

90

(2,5)

(5,{3,6})

25

57

82

(2,6)

(6,{3,5})

21

46

67=F3(2,{3,5,6})

(2,{4,5,6})

(2,4)

(4,{5,6})

30

73

103

(2,5)

(5,{4,6})

25

72

97

(2,6)

(6,{4,5})

21

56

77=F3(2,{4,5,6})

(3,{2,4,5})

(3,2)

(2,{4,5})

19

69

88

(3,4)

(4,{2,5})

5

47

52=F3(3,{2,4,5})

(3,5)

(5,{2,4})

10

54

64

(3,{2,4,6})

(3,2)

(2,{4,6})

19

75

94

(3,4)

(4,{2,6})

5

50

55=F3(3,{2,4,6})

(3,6)

(6,{2,4})

15

64

79

(3,{2,5,6})

(3,2)

(2,{5,6})

19

78

97

(3,5)

(5,{2,6})

10

52

62=F3(3,{2,5,6})

(3,6)

(6,{2,5})

15

51

66

(3,{4,5,6})

(3,4)

(4,{5,6})

5

73

78

(3,5)

(5,{4,6})

10

72

82

(3,6)

(6,{4,5})

15

56

71=F3(3,{4,5,6})

(4,{2,3,5})

(4,2)

(2,{3,5})

32

59

91

(4,3)

(3,{2,5})

4

49

53

(4,5)

(5,{2,3})

8

42

50=F3(4,{2,3,5})

(4,{2,3,6})

(4,2)

(2,{3,6})

32

60

92

(4,3)

(3,{2,6})

4

49

53=F3(4,{2,3,6})

(4,6)

(6,{2,3})

16

47

63

(4,{2,5,6})

(4,2)

(2,{5,6})

32

78

110

(4,5)

(5,{2,6})

8

52

60=F3(4,{2,5,6})

(4,6)

(6,{2,5})

16

51

67

(4,{3,5,6})

(4,3)

(3,{5,6})

4

72

76

(4,5)

(5,{3,6})

8

57

65

(4,6)

(6,{3,5})

16

46

62=F3(4,{3,5,6})

(5,{2,3,4})

(5,2)

(2,{3,4})

27

57

84

(5,3)

(3,{2,4})

11

49

60

(5,4)

(4,{2,3})

10

34

44=F3(5,{2,3,4})

(5,{2,3,6})

(5,2)

(2,{3,6})

27

60

87

(5,3)

(3,{2,6})

11

49

60=F3(5,{2,3,6})

(5,6)

(6,{2,3})

18

47

65

(5,{2,4,6})

(5,2)

(2,{4,6})

27

75

102

(5,4)

(4,{2,6})

10

50

60=F3(5,{2,4,6})

(5,6)

(6,{2,4})

18

64

82

(5,{3,4,6})

(5,3)

(3,{4,6})

11

69

80

(5,4)

(4,{3,6})

10

55

65=F3(5,{3,4,6})

(5,6)

(6,{3,4})

18

47

65=F3(5,{3,4,6})

(6,{2,3,4})

(6,2)

(2,{3,4})

22

57

79

(6,3)

(3,{2,4})

16

49

65

(6,4)

(4,{2,3})

20

34

54=F3(6,{2,3,4})

(6,{2,3,5})

(6,2)

(2,{3,5})

22

59

81

(6,3)

(3,{2,5})

16

49

65

(6,5)

(5,{2,3})

12

42

54=F3(6,{2,3,5})

(6,{2,4,5})

(6,2)

(2,{4,5})

22

69

91

(6,4)

(4,{2,5})

20

47

67

(6,5)

(5,{2,4})

12

54

66=F3(6,{2,4,5})

(6,{3,4,5})

(6,3)

(3,{4,5})

16

54

70

(6,4)

(4,{3,5})

20

42

62

(6,5)

(5,{3,4})

12

37

49=F3(6,{3,4,5})

 

 

5k=2时,F2(i,S2) = min{D[i,j] + F3(j,S3)}      i=2,3,4,5,6

 

X2=(i,S2)

U2=(i,j)

X3=(j,S3)

V2=D[i,j]

F3(j,S3)

V2 + F3(j,S3)

(2,{3,4,5,6})

(2,3)

(3,{4,5,6})

18

71

89

(2,4)

(4,{3,5,6})

30

62

92

(2,5)

(5,{3,4,6})

25

65

90

(2,6)

(6,{3,4,5})

21

49

70=F2(2,{3,4,5,6})

(3,{2,4,5,6})

(3,2)

(2,{4,5,6})

19

77

96

(3,4)

(4,{2,5,6})

5

60

65=F2(3,{2,4,5,6})

(3,5)

(5,{2,4,6})

10

60

70

(3,6)

(6,{2,4,5})

15

66

81

(4,{2,3,5,6})

(4,2)

(2,{3,5,6})

32

67

99

(4,3)

(3,{2,5,6})

4

62

66=F2(4,{2,3,5,6})

(4,5)

(5,{2,3,6})

8

60

68

(4,6)

(6,{2,3,5})

16

54

70

(5,{2,3,4,6})

(5,2)

(2,{3,4,6})

27

68

95

(5,3)

(3,{2,4,6})

11

55

66

(5,4)

(4,{2,3,6})

10

53

63=F2(5,{2,3,4,6})

(5,6)

(6,{2,3,4})

18

54

72

(6,{2,3,4,5})

(6,2)

(2,{3,4,5})

22

62

84

(6,3)

(3,{2,4,5})

16

52

68

(6,4)

(4,{2,3,5})

20

50

70

(6,5)

(5,{2,3,4})

12

44

56=F2(6,{2,3,4,5})

 

6k=1时,F1(1,S1) = min{D[1,j] + F2(j,S2)}

 

X1=(1,S1)

U1=(1,j)

X2=(j,S2)

V1=D[1,j]

F2(j,S2)

V1 + F2(j,S2)

(1,{2,3,4,5,6})

(1,2)

(2,{3,4,5,6})

10

70

80=F1(1,{2,3,4,5,6})

(1,3)

(3,{2,4,5,6})

20

65

85

(1,4)

(4,{2,3,5,6})

30

66

96

(1,5)

(5,{2,3,4,6})

40

63

103

(1,6)

(6,{2,3,4,5})

50

56

106

 

 

3、伪代码和C++源码

为方便计算,结点编号改为05.

(1)用一张二维表格F[][]表示F(i,Sk),行数是n,列数是2n-1

(2)行号表示当前所在的结点i

列号对应的五位二进制表示表示{V5,V4,V3,V2,V1}的一个子集,1表示在集合中,0表示不在集合中。

例如:00110表示的集合为{V3,V2}00000表示空集

(3)再用一张n*2n-1的表格M[][]存储对应每个状态(iSk)所做的最优决策,以便回溯找最短路线。

 

伪代码:

TSP(int D[][]int n)

//输入n个顶点的有向图,矩阵D[][]是有向图的邻接矩阵

//D[][]是原图的邻接矩阵

//F[][]中存储阶段最短路径,M[][]中存储阶段最优策略,行数是n,列数是2n-1

//找到从V0出发,遍历所有城市一次且仅一次再回到V0的最短路径长度

//并输出最短路径

{

       for(i=0; i<n; i++)

              F[i][0] = D[i][0];  //初始化第0列,F6(i,Φ)= D[i,0]

      

for(i=1; i<2n-1-1; i++)  //

       for(j=1;j<n; j++)  //

              if(j不在i的二进制表示对应的集合中)

                     对于i对应集合中的每一个点k

{                   

计算D[j][k]+F[k][i-2k-1]并选择使之取得最小值mink*; 

                            F[k][i]= min ; //填表,记录阶段最优值

                            M[k][i]= k* ;  //记录每个状态的最优决策k*

}

 

//i==2n-1-1

对于i中的每个节点k

计算D[0][k] + F[k][ [i-2k-1]并选择使之取得最小值mink*

F[0][ 2n-1-1] = min; //总最短路径

M[0][ 2n-1-1] = k*;

 

//回溯查表M输出最短路径

输出V0

for(2n-1-1,j=0; i>0; )

{

       j =M[j][i];//下一步去往哪个结点

       i = i –2j-1;//i表示的集合中删除j

       输出Vj

}

}

C++源码:

#include<iostream.h>
#include<fstream.h>
#include<stdlib.h>
#include<math.h>

#define n 6     //结点个数

void main()
{
	int i,j,k,min,temp;
	int b=(int)pow(2,n-1);
	int D[20][20];//原图的邻接矩阵
	
	fstream fin("TSPinput1.txt",ios::in);//打开输入文件
	fstream fout("TSPoutput.txt",ios::out);//打开输出文件

	//读入数据到邻接矩阵D中
	for(i=0;i<n;i++)
		for(j=0;j<n;j++)
			fin>>D[i][j];

	//申请二维数组F和M
	int ** F = new int* [n];//n行b列的二维数组,存放阶段最优值
	int ** M = new int* [n];//n行b列的二维数组,存放最优策略
	for(i=0;i<n;i++)
	{
		F[i] = new int[b];//每行有2的n-1次方列
		M[i] = new int[b];
	}

	//初始化F[][]和M[][]
	for(i=0;i<b;i++)
		for(j=0;j<n;j++)
		{
			F[j][i] = -1;
			M[j][i] = -1;
		}
	
	//给F的第0列赋初值
	for(i=0;i<n;i++)
		F[i][0] = D[i][0];
		
	//遍历并填表
	for(i=1;i<b-1;i++)//最后一列不在循环里计算
		for(j=1;j<n;j++)
		{
			//int p=(int)pow(2,j-1);
			//int res=p & i;
			if( ((int)pow(2,j-1) & i) == 0)//结点j不在i表示的集合中
			{
				min=65535;
				for(k=1;k<n;k++)
					if( (int)pow(2,k-1) & i )//非零表示结点k在集合中
					{
						temp = D[j][k] + F[k][i-(int)pow(2,k-1)]; 
						if(temp < min)
						{
							min = temp;
							F[j][i] = min;//保存阶段最优值
							M[j][i] = k;//保存最优决策
						}
					}
		
			}
		}
		
	//最后一列,即总最优值的计算
	min=65535;
	for(k=1;k<n;k++)
	{
		//b-1的二进制全1,表示集合{1,2,3,4,5},从中去掉k结点即将k对应的二进制位置0
		temp = D[0][k] + F[k][b-1 - (int)pow(2,k-1)];
		if(temp < min)
		{
			min = temp;
			F[0][b-1] = min;//总最优解
			M[0][b-1] = k;
		}
	}
	fout<<"最短路径长度:"<<F[0][b-1]<<endl;//最短路径长度


	//回溯查表M输出最短路径(编号0~n-1)
	fout<<"最短路径(编号0—n-1):"<<"0";
	for(i=b-1,j=0; i>0; )//i的二进制是5个1,表示集合{1,2,3,4,5}
	{
		j = M[j][i];//下一步去往哪个结点
		i = i - (int)pow(2,j-1);//从i中去掉j结点
		fout<<"->"<<j;
	}
	fout<<"->0"<<endl;

	//输出表格F到文件
	for(i=0;i<n;i++)
	{
		for(j=0;j<b;j++)
			fout<<F[i][j]<<" ";
		fout<<endl;
	}

}


 

源码及测试数据下载地址:http://download.csdn.net/detail/masikkk/4822942

 

 

 

旅行问题(Traveling Salesman Problem, TSP)是一个经典的组合优化问题,目标是最小化一个旅行从一系列城市出发,访问每个城市一次并返回起点的总行程长度。Python可以使用多种算法求解TSP,包括暴力搜索、动态规划、遗传算法、模拟退火等。 1. **暴力搜索**:如Brute Force,穷举所有可能的路径,计算每种路径的总长度,找到最短的那个。但这对于大量城市的问题来说效率极低,因为搜索空间呈指数级增长。 2. **动态规划**:例如 Held-Karp 算法,利用上一状态的信息逐步构建最优解,虽然复杂度较高,但对于一些较小规模的实例效果较好。 3. **近似算法**:像 Christofides 算法、Ant Colony Optimization 或者 Genetic Algorithms(遗传算法),通过概率模拟寻找接近全局最优的解,通常用于大规模问题。 4. **启发式搜索**:例如 nearest neighbor (NN) 或者 2-opt 等局部优化策略,在一个初始解的基础上不断改进。 在Python中,你可以使用`networkx`库来构建图,并结合`scipy.optimize`中的`anneal`函数实现模拟退火等优化算法。这里有一个简化的例子: ```python import networkx as nx from scipy.optimize import dual_annealing # 定义TSP问题的函数,输入是城市的列表,输出是路径长度 def tsp_cost(cities): graph = nx.complete_graph(cities) path = nx.shortest_path(graph, source=0) # 使用最短路径算法得到初步解 return sum(nx.euclidean_distance(graph, u, v) for u, v in zip(path[:-1], path[1:])) # 调用模拟退火算法求解 cities = ... # 假设你有城市坐标列表 result = dual_annealing(tsp_cost, bounds=[(i, i+1) for i in range(len(cities))], annealing schedule='boltzmann', initial_temp=1e6) print("最优路径:", result.x, "对应的总长度:", tsp_cost(result.x))
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值