Fork me on GitHub

随机法解决TSP问题

TSP问题一直是个头疼的问题,但是解决的方法数不胜数,很多的算法也都能解决。百度资料一大堆,但是我找到了代码比较简练的一种。随机法。下面只是个人的看法而已,如果有任何问题虚心接受。

 

顾名思义,随机法就是随机一个序列然后用这个序列去解决问题。

TSP问题描述中,一个人走一圈回到原点要使走过的路程最短,那么他一定有一个路径,随机法,随机的就是这个路径。

首先我们要明白的是,只要随机的量足够大,最终一定能得到结果,因为能随机到枚举的全部。

第二,随机了一个路径之后,我们要在这个路径下面找到最短的路径,方法是通过交换两个位置得到的。

第三,要根据题目意思,确定图不是很大,或者数据量并非那种特别巨大的题目,也就是说看清题目。灵活选用方法。

 

1、我们随机一个路线出来

0-3-1-2-0(最终是要返回0的)

2、我们根据这个路径找到这个路径的路程s。

3、除了首尾的0之外,交换任意两个数,如果交换完了之后s变小了,就更新s

 

听上去是不是觉得这个算法很扯,是不是感觉最终得不到最优解,可是当你循环个50000次试试,你就知道,基本上99%都能拿到最优解,这个比暴力搜索快,但是比dp不稳,这个算法的有点在于编码不复杂,而且在基本问题上面都能得到最优解,所以最终我选择了这个。

 

下面附上代码:

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>

using namespace std;
/*TSP随机法*/

int n;//图的大小
int maps[20][20];//记录任意两点的距离
int order[20];//记录行走的顺序

//计算当前行走顺序下的距离
int dis()
{
    int nowDis=0;
    int i;
    //因为是从0开始走最后返回所以是n+1
    for (i = 1; i <= n+1; i++)
    {
        nowDis += maps[order[i-1]][order[i]];
    }
    return nowDis;
}

int main()
{
    int i,j;
    int answer;//记录答案
    int result;//记录最终输出
    int ready=0;//记录是否成功
    int temp;//临时变量
    cin>>n;
    //用户输入家到任意一点的距离,保存在第一行中
    for (i = 1; i <= n; i++)
    {
        cin>>maps[0][i];
         maps[i][0] = maps[0][i];
    }
    //用户输入任意两点间的距离
    for (i = 1; i <= n; i++)
    {
        for (j = 1; j <= n; j++)
        {
            cin>>maps[i][j];
            maps[j][i] = maps[i][j];
        }
    }

    result = 999999999;
    //下面是随机开始

    int t;//随机的次数
    for (t = 0; t < 50000; t++)
    {
        //初始化随机序列
        for (i = 1; i <= n; i++)
            order[i] = i;
        order[0] = 0;//一定是从0点开始走
        order[n+1] = 0;//一定最终回到0点

        //交换任意随机序列中的值,不动0点和n+1点的值
        for (i = 1; i <= n; i++)
        {
            j = rand()%n + 1;
            swap(order[i],order[j]);
        }

        //获取当前最短路
        answer = dis();
        while (true)
        {
            ready = 0;
            for (i = 1; i <= n; i++)
            {
                for (j = i+1; j <= n; j++)
                {
                    //交换每两个值
                    swap(order[i],order[j]);
                    temp = dis();
                    //如果当前交换之后,比当前路径小,那么就更新值
                    if(temp < answer)
                    {
                        answer = temp;
                        ready = 1;
                    }
                    else//如果不比当前小,交换回来
                        swap(order[i],order[j]);
                }
            }
            //只要有一次交换,那么就再一次循环,确保不存在更小的路径
            if(ready == 0)
                break;
        }

        if(result > answer)
            result = answer;
    }
    cout<<result<<endl;
    return 0;
}
posted @ 2016-04-19 00:56  LinkinStar  阅读(1801)  评论(0编辑  收藏  举报