TSP hdu 5418

hdu 5418

这道题是到最基础的状压dp,外加一个floyid距离问题(最短距离).

大概题意是有个人从1号位置出发,经过其他n-1个位置又回到1号位置,并且要求其他的地方至少都要走一遍,告诉有m条路径,每条路径都有个起点和终点,还有走这条路径需要的花费,最后求走完所有的地方花费最少是多少?

下边来看代码:

#include<iostream>
#include<cstdio>
using namespace std;
#include<cstring>
int a[18][18],dp[18][1<<18];
const int inf=0x3f3f3f3f;
int n,m;
void floyid()//floyid距离,最短距离的求法
{
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        a[i][j]=min(a[i][j],a[i][k]+a[k][j]);
}
int  main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        int u,v,t;
        for(int i=1;i<=n;i++)//对距离初始化
            {
                for(int j=1;j<=n;j++)
                a[i][j]=(i==j)?0:inf;
            }
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&u,&v,&t);
            if(t<a[u][v])a[u][v]=a[v][u]=t;//这里很容易漏掉,因为观察到题目中n和m的范围才发现,这是个陷阱,1<=n<=16,1<=m<=100000,这里的m太大了,也就是路劲数出奇的多,假设所有的地点都用上,路径数最多也就是16*16,不会有10w,所以一定有一些两点之间的路径重复给出,所以要取其中最小的哦。。。
        }
        if(n==1){cout<<0<<endl;continue;}
        floyid();
        memset(dp,inf,sizeof dp);
        dp[1][1]=0;
        for(int s=1;s<(1<<n);s++)
        {
            for(int i=1;i<=n;i++)
                    if(s&(1<<i-1))continue;//状态转移的时候,需要这个被转移的地点还没有走过,如果走过了,那么直接就是pass掉了
                    else {
                        for(int k=1;k<=n;k++)
                        if(s&(1<<k-1)){//要求中间的节点k一定已经走过了,只有这样才可以继续由这个中间节点到达最后的状态转移的i节点
                            dp[i][s|(1<<i-1)]=min(dp[i][s|(1<<i-1)],dp[k][s]+a[k][i]);
                        }
                    }
        }
//        for(int i=1;i<=n;i++)
//        {
//            cout<<i<<":"<<dp[i][(1<<n)-1]<<endl;
//        }
        int minn=inf;
        for(int i=2;i<=n;i++)//这里是算加上第i个地点回到1的距离,最后取最小的
            minn=min(minn,dp[i][(1<<n)-1]+a[i][1]);
        printf("%d\n",minn);
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值