hdu 3001 Travelling (TSP问题,状压dp)

After coding so many days,Mr Acmer wants to have a good rest.So travelling is the best choice!He has decided to visit n cities(he insists on seeing all the cities!And he does not mind which city being his start station because superman can bring him to any city at first but only once.), and of course there are m roads here,following a fee as usual.But Mr Acmer gets bored so easily that he doesn't want to visit a city more than twice!And he is so mean that he wants to minimize the total fee!He is lazy you see.So he turns to you for help.
Input
There are several test cases,the first line is two intergers n(1<=n<=10) and m,which means he needs to visit n cities and there are m roads he can choose,then m lines follow,each line will include three intergers a,b and c(1<=a,b<=n),means there is a road between a and b and the cost is of course c.Input to the End Of File.
Output
Output the minimum fee that he should pay,or -1 if he can't find such a route.
Sample Input
2 1
1 2 100
3 2
1 2 40
2 3 50
3 3
1 2 3
1 3 4
2 3 10
Sample Output
100
90

7

百度百科的TSP问题

关于TSP(旅行商)问题

1、二进制tsp问题求解

2、三进制tsp问题求解

3、模拟退火算法tsp问题(还没学会

首先tsp(旅行商问题)问题是指有一个旅行商要去n个城市,这n个城市之间有不同的距离,问要走遍这n个城市且每个城市只走一次的最短路径是多少(个人理解,非官方的说法)。

那上面是二进制tsp,因为每个城市只有走和不走两种状态,可以状压dp求解。关于三进制就是每个城市可以最多走2次,每个城市有三个状态。

求解tsp问题的算法有很多,比如:模拟退火,遗传算法,蚁群算法,粒子群算法,动态规划算法。

因为tsp问题是NP问题,除了动态规划算法其他的好像都是概率性质的算法,主要想学一下模拟退化算法。关于动态规划算法也比较好理解,很多文章讲的是递归dp然后优化,其实本质都是状态压缩的dp

下面给出一个三进制的tsp问题的题目,也是用状态压缩做的,二进制同理。

/*题目描述:有n个城市,每个城市最多走2次,有m个语句描述边的距离,然后求经历过n个城市的最小的距离,不限制起点和终点*/

#include <cstring>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>

using namespace std;
int mp[12][12],n,dp[12][60000];
int arr(int three[],int sum)
{
    int k=0;
    for(int i=0; i<n; i++)
    {
        three[i]=sum%3;
        sum/=3;
        if(three[i])k++;
    }
    return k;
}
int main()
{
    int m,a,b,c,in[12],MIN,three[12],k;
    in[0]=1;
    for(int i=1; i<=10; i++)in[i]=in[i-1]*3;
    while(~scanf("%d%d",&n,&m))
    {
        for(int i=0; i<n; i++)
        {
            for(int j=0; j<in[n]; j++)
            {
                dp[i][j]=-1;
            }
            for(int j=0; j<n; j++)
                mp[i][j]=-1;
        }
        for(int i=0; i<m; i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            a--;
            b--;
            if(mp[a][b]!=-1)
                mp[a][b]=mp[b][a]=min(c,mp[a][b]);
            else mp[a][b]=mp[b][a]=c;
        }
        MIN=-1;
        for(int go=1; go<in[n]; go++)///从初始状态往下推导,即从只有终点开始
            ///能通过终点而找出的其他状态进行更新,如果不能到达的状态说明是不可达的了。
        {
            k=arr(three,go);
            for(int i=0; i<n; i++)///枚举的是终点
            {
                if(three[i])
                {
                    if(k==1)dp[i][go]=0;
                    if(dp[i][go]==-1)continue;///当到达这个状态时还没有从终点推导过来,说明是不可达的
                    if(k==n)
                    {
                        if(MIN==-1)MIN=dp[i][go];
                        else MIN=min(MIN,dp[i][go]);
                    }
                    for(int j=0; j<n; j++)///从终点往前推导,再经过j一次
                    {
                        if(i!=j&&three[j]<2&&mp[i][j]!=-1)
                        {
                            int tgo=go+in[j];///表示在三进制中在j这个位置上的数加上1,表示以j为结尾,
        ///也就是j又来过一次,通过i点
                            if(dp[j][tgo]==-1)
                                dp[j][tgo]=dp[i][go]+mp[i][j];
                            else dp[j][tgo]=min(dp[i][go]+mp[i][j],dp[j][tgo]);
                        }
                    }
                }
            }
        }
        printf("%d\n",MIN);
    }
    return 0;
}



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值