动态规划解决旅行商问题附代码x

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
void getJ(int jlist[], int c, int n)// 根据 2 进制 j 和 j 中 1 的个数找下一个 j {
int i = n-1,j; int tmp = 1 , result = 0; while(!jlist[i])i--;// 最高位的 1 的位置 j = i-1; while(jlist[j])j--;// 找最高位 1 之下的最高 0 if(!jlist[n-1])// 若最高位不为 1 {
邻接矩阵 :
node
0
1
2
3
0
5
3
2
1
5
7
9
2
3
7
12
3
2
9
12
动态填表 : 表中元素代表第 i 个节点经过 V 集合中的点最后到 个值 ,取其中最小的一个 .
0 点的最短值 .如果有多
------------word 文档可编辑 -------------
i\Vj 0 1
2
3
1,2(取 min) 1,3(取 min) 2,3(取 min) 1,2,3( 取 min)
int nextj = 0;// 下一个 j int c=0;// 计数 j 的二进制有几个 1 int jlist[20]={0};// 存放 j 的二进制数组 int i=0; int tmp = 1; while(j) {
if(j%2) {
c++; jlist[i++]=1; }else { jlist[i++]=0; } j/=2; } getJ(jlist,c,N-1);// 处理 jlist
d[2][{1}]=24}
这样一共循环 (2^(N-1)-1)*(N-1) 次,就把时间复杂度缩小到 O(N*2 N )的级别 . 核心伪代码如下 :
{ for (i =1;i<n;i++)
d[i][0]=c[i][0];
// 初始化第 0 列
for( j=1;j<2^(N-1)-1;j++)
for(i=1 ; i<n ;i++)
d(i,V ’ ) = minik{c+ d(k,V -’{k})} (k ∈ V’ )
1)
d(k,{}) = c ki (k ≠ i)
2)
简单来说 ,就是用递归表达 :从出发点 0 到 1 号点 ,假设 1 是第一个 ,则剩下的
路程就是从 1 的时候 ,
printf("%d\n",min); getchar(); return 0; }
------------word 文档可编辑 -------------
//2^n 次方解法 for (i =1;i<N;i++)
d[i][0]=matr[i][0];
//初始化第 0 列
for(j=1;j<pow(2,N-1)-1;j=getnextj(j)) for(i=1; i<N ;i++) { if(!(j & ( 1<<(i-1) )))// 如果集合 j 中不包含 i { //对 V[j] 中的每个元素 k,计算 d[i][j] = min{matr[i][k] + d[k][{j-k}]}; int jlist[20]={0}; // 存放 j 的二进制数组 int tmpres[20]={0}; int c=0,k=j,l; while(k) { if(k%2) { jlist[c++]=1; }else { jlist[c++]=0; } k/=2; } c=0; for(l=0;l<N;l++) { if(jlist[l]) { tmpres[c++]=matr[i][l+1] + d[l+1][j-(1<<l)]; } } d[i][j] = getmin(tmpres);
scanf("%d",&N);// 读入点数
------------word 文档可编辑 -------------
for(i = 0; i < N; i++)// 读入邻接矩阵 {
for(j = 0;j < N; j++) {
scanf("%d",&matr[i][j]); } } int V[20]={0}; for(i = 0; i < N; i++)V[i]=1;// 将所有点设置为未经过点 V[0]=0;// 以第 0 个点为出发点
------------word 文档可编辑 -------------
#include <ctime> #include <algorithm> using namespace std;
int N;// 节点数 int matr[20][20];// 存邻接矩阵 int d[20][40000]={0};// 存动态填表数据
------------word 文档可编辑 -------------
while(!jlist[j])j--;// 找和最高位隔着 0 的最高 1 for(i=0;j+i<n;i++)jlist[j+i]=0; for(i=0;i<=k;i++)jlist[j+i+1]=1; }
}
int getnextj( int j ) {
1. 问题基本描述 :
求一个旅行商经过 N 个城市最后回到出发点的最短路径 . 即 ,在一个无向带权图的邻接矩阵中 ,求一个最短环包括所有顶点 .
2. 解法 :
1) 动态规划 :
假设从顶点 i 出发,令 d(i,V’)表示从顶点 i 出发经过 V’中各个顶点一次且仅一次,
最后回到出发点 i 的最短路径的长度,开始时, V’=V-{i} ,于是,旅行商问题的动态 规划函数为:
------------word 文档可编辑 -------------
} } int tmpres[20]={0}; j = pow(2,N-1)-1; for(i=1;i<N;i++) { tmpres[i]=matr[0][i] + d[i][ j - (1<<(i-1) )]; } min = getmin(tmpres); //对 V[2^(n-1)-1] 中的每个元素 k,计算 : // d[0][2^(n-1)-1] = min{matr[0][k] + d[k][2^(n-1)-2]}; //输出最短路径 :d[0][2^(n-1)-1];
d(k,{}) = c ki (k ≠, i)找的是最后一个点到 0 点的距离 .递归求解 1 之后 ,再继续求 V’ 之中剩下的点 ,最后找出 min.
如果按照这个思想直接做 ,对于每一个 i 都要递归剩下的 V 中所有的点 ,所以
这样的时间复杂度就近似于 N!,其中有很多重复的工作 .
可以从小的集合到大的集合算 ,并存入一个二维数组 ,这样当加入一个节点 时,就可以用到之前的结果 ,如四个点的情况 :
//将为 1 的最高一位向上移一位 jlist[i]=0; jlist[i+1]=1; }else if(n-1-j==c)// 若最高位为 1, 且 j 为当前 1 的个数所能组成的最大的 j { for(i=0;i<n;i++)jlist[i]=0; for(i=0;i<c+1;i++)jlist[i]=1; }else// 最高位为 1, 且在当前数目 1 下还能变更大 { //将和最高位之间有隔 0 的最高的 1 上移一位 ,并把这个 1 之后的 所有 1 拉到紧邻它后面 int k; k=n-1-j;// 最高位一共有多少相邻的 1
输出最短路径 :d[0][2^(n-1)-1];
}
具体代码如下 : // TravRoadD.cpp : Defines the entry point for the console application. //
#include "stdafx.h" #include "windows.h" #include "math.h" #include <stdio.h>
{
if( 子集 Vj 中不包含 i){
每一个 k∈ Vj};
对 Vj 中的每个元素 k,计算 d[i][Vj] = min{c[i][k] + d[k][{Vj-k}] |
}
}
对 V[2^(n-1)-1] 中的每个元素 k,计算 :
d[0][2^(n-1)-1] = min{c[0][k] + d[k][2^(n-1)-2]};
for(i=0;i<N-1;i++)// 将 jlist 中的 2 进制转换成 int 返回 {
if(jlist[i]) nextj += tmp;
tmp *= 2; } return nextj; }
int main(int argc, char* argv[]) {
freopen("d:\\test_20.txt","r",stdin); int i,j; int min;
0
c[0][i]+d[i][v ’]=21
1
5
10 11
{c[1][2]+ d[2][{3}]=21, c[1][3]+ d[3][{2}]=24}
2
3 12
14
{c[2][1]+ d[1][{3}]=18, c[2][3]+ d[3][{1}]=26}
3
2 14 15
{c[3][1]+ d[1][{2}]=19, c[3][2]+
int getmin(int *sum)// 返回该数组中最小非零值 {
int i = 0; int min = -1,k; for(;i<N;i++) {
if((min < 0 && sum[i]>0) || (sum[i]>0 && sum[i]<min)) {
min = sum[i];k = i; } } return min; }
相关文档
最新文档