旅行商问题 回溯法

  • 问题描述:

这个问题要求找出一条n个给定的城市间的最短路径,使我们在回到触发的城市之前,对每个城市都只访问一次。

  • 图解:

如图所示

  • 解决方法:

回溯法就是蛮力算法,把所有的可能性都试一次,从里面找出来最优解。这里用的是子集树。因为不能一个城市去多次,所以加一个城市的标记,初始值都是0,如果去过就变成1。

  • 代码:

/*
	回溯法(子集树) 
*/ 
#include <stdio.h> 
 # include <stdlib.h>  
# include <time.h>
#define N 200                //城市数目  
#define NO_PATH -1         //没有通路  
#define MAX_WEIGHT 4000  
int City_Graph[N+1][N+1];  //保存图信息  
int x[N+1];                //x[i]保存第i步遍历的城市  
int isIn[N+1];             //保存 城市i是否已经加入路径  
int bestw;                 //最优路径总权值  
int cw;                    //当前路径总权值
int bw;                    //深度搜索完成总权值
int bestx[N+1];            //最优路径  
//-----------------------------------------------------------------  
void Travel_Backtrack(int t)
{   //递归法  
    int i,j;  
    if(t>N)
	{                         //走完了,输出结果  
        for(i=1;i<=N;i++)            //输出当前的路径  
            printf("%d ",x[i]);
		printf("\n");
		bw = cw + City_Graph[x[N]][1]; //返回起点,需要加上从第n个到第一个的距离 
        if(bw < bestw) //挑选出最优总权值
		{                
            for (i=1;i<=N;i++)
			{  
                bestx[i] = x[i];  //把每一步的路径保存下来 
            } 
			bestw = bw; // 更新最优解 
        }  
        return;  
    }  
    else
	{  
        for(j=2;j<=N;j++)//因为出发点为1号,所以后面回溯时1号不满足后面的if条件
		{           //找到第t步能走的城市  
            if(City_Graph[x[t-1]][j] != NO_PATH && !isIn[j] /*&& cw<bestw*/)//剪枝条件:可达且未加入到路径中且当前总权值小于最优权值
			{   
                isIn[j] = 1; // 标记走过了 
                x[t] = j;  
                cw += City_Graph[x[t-1]][j];  
                Travel_Backtrack(t+1); 
                isIn[j] = 0; 
                x[t] = 0;  
                cw -= City_Graph[x[t-1]][j];  
            }  
        }  
    }  
}  
int main(void)
{  
    int i; 
	int j; 
   	srand((unsigned)time(NULL));
    for(i = 1; i <= N; i++) {
		for(j = 1; j <= N; j++) {
			int num = 0;
			num = rand() % 201;
			City_Graph[i][j] = num;
			printf("%d ", City_Graph[i][j]);
		} 
	} 
    //测试递归法,初始化  
    for (i=1;i<=N;i++)
	{  
        x[i] = 0;               //表示第i步还没有解  
        bestx[i] = 0;           //还没有最优解  
        isIn[i] = 0;            //表示第i个城市还没有加入到路径中  
    }  
       
    x[1] = 1;                   //第一步 走城市1  
    isIn[1] = 1;                //第一个城市 加入路径  
    bestw = MAX_WEIGHT;  		// 因为要求最小值先设置为极大值 
    cw = 0;  					// 用于保存每一种可能的路径和值 
    Travel_Backtrack(2);        //从第二步开始选择城市  
    printf("最优值为%d\n",bestw);  
    printf("最优解为:\n");  
    for(i=1;i<=N;i++)
	{  
        printf("%d ",bestx[i]);  
    }  
    printf("\n");
	return 0;  
}  
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值