CODEVS 2800 送外卖

本文介绍了一种使用状态压缩动态规划解决特定路径寻找问题的方法。问题要求找到从起点出发,遍历所有指定节点后返回起点所需的最短时间。文章详细解释了状态压缩的概念及其在动态规划中的应用,并通过具体代码示例展示了实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述:从0号点出发,经过1-n点,不要求顺序,而且每个点可以走多次,最后回到0点,求最短时间。
因为要走遍1-n点,那么直接最短路是不行的,不保证没有环,所以dfs时间会多一些,而且这里dfs不好剪枝,那么就可以考虑一下dp,状态就是到某个点,走过了一些点,所用的最短时间,那么就要记录走过了哪些点,用bool数组存并不好,因为dp数组要开二维,而且判断哪些点走过时还要去枚举每个点去判断,既费时又费力。所以这个蹩脚的事情推动IT精英们去发明了状态压缩,留给我们使用。
状态压缩,顾名思义,就是压缩了状态(怎么感觉什么都没有说),直接拿这个题当栗子,有三个点,那么关于这三个点有没有走过的问题,可以用这些数来表示:000、001、010、011、100、101、110、111。很容易看出这是二进制,而且一共2ⁿ个,状态就这样地表示出来了,那么怎么这样怎么进行状态记录和转移呢,在我们新到达点i的时候我们可以让状态 +=2的i次方 ;我们查询点i有没有被走过,可以让状态 |2的i次方,这样处理完之后如果状态改变了那么就说明点i没有被走过(只有在i那个位置为0的时候才会改变)。
另外这个题要提前floyd求一下每两个点之间的最短路。

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int g[20][20],dp[20][(1<<16)];
int min(int a,int b)
{
    return (a<b)?a:b;
}
int main()
{
    int n;
    cin>>n;
    for (int i=0;i<=n;i++)
        for (int j=0;j<=n;j++)
            scanf("%d",&g[i][j]);
    for (int k=0;k<=n;k++)
        for (int i=0;i<=n;i++)
            if (i!=k)
                for (int j=0;j<=n;j++)
                    if (j!=k&&j!=i)
                        g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
    memset(dp,127/3,sizeof(dp));
    dp[0][0]=0;
    int len=(1<<(n+1))-1;
    for (int k=0;k<=len;k++)    //枚举走的情况
        for (int i=0;i<=n;i++)  //枚举终点,下面那个是枚举起点
        {
            if ((k|(1<<i))!=k) continue;
            for (int j=0;j<=n;j++) dp[i][k]=min(dp[i][k],min(dp[j][k-(1<<i)],dp[j][k])+g[j][i]);
        }       
    cout<<dp[0][len];
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值