hdu4385(状态压缩dp)

本文介绍了一个关于寻找通过所有点的最短路径和的问题,并提供了一段C++代码实现。该算法利用动态规划来解决从起点出发,经过所有点再返回起点的最短路径和问题。代码中使用了位操作来表示状态,以及距离矩阵来计算点之间的距离。

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

链接:点击打开链接

题意:有n个点,每次可以从起点出经过一个点或者两个点回到起点,问所有点都经过后所需最小的路径和

代码:

#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
struct node{
    int x,y;
}s[50];
int dp[1<<21],pre[1<<21],dis[50][50];
bool cmp(int a,int b){
    return (a&(-a))<(b&(-b));
}
int main(){
    int t,n,i,j,k,cas,sta,siz,num;
    cas=1;
    scanf("%d",&t);
    while(t--){
        vector<int> G;
        scanf("%d%d",&s[0].x,&s[0].y);
        scanf("%d",&n);
        for(i=1;i<=n;i++)
        scanf("%d%d",&s[i].x,&s[i].y);
        for(i=0;i<=n;i++)
        for(j=i;j<=n;j++)
        dis[i][j]=dis[j][i]=(s[i].x-s[j].x)*(s[i].x-s[j].x)+(s[i].y-s[j].y)*(s[i].y-s[j].y);
        memset(dp,INF,sizeof(dp));
        memset(pre,0,sizeof(pre));
        dp[0]=0;                                //dp[s]表示状态是s时最小路径和
        for(sta=0;sta<(1<<n);sta++){
            for(j=1;j<=n;j++){
                if(sta&(1<<(j-1)))
                continue;
                if(dp[sta|(1<<(j-1))]>dp[sta]+dis[0][j]*2){
                dp[sta|(1<<(j-1))]=dp[sta]+dis[0][j]*2;
                pre[sta|(1<<(j-1))]=sta;
                }                               //每次搬一个
                for(k=j+1;k<=n;k++){
                    if(sta&(1<<(k-1)))
                    continue;
                    if(dp[sta|(1<<(j-1))|(1<<(k-1))]>dp[sta]+dis[0][j]+dis[j][k]+dis[0][k]){
                    dp[sta|(1<<(j-1))|(1<<(k-1))]=dp[sta]+dis[0][j]+dis[j][k]+dis[0][k];
                    pre[sta|(1<<(j-1))|(1<<(k-1))]=sta;
                    }                           //每次搬两个
                }                               //用pre数组记录每个状态上一个状态,最后用一次异或求出
            }                                   //用了哪个点
        }
        printf("Case %d:\n",cas++);
        printf("%d\n",dp[(1<<n)-1]);
        for(i=(1<<n)-1;i>0;i=pre[i]){
        G.push_back(i^pre[i]);
        }
        sort(G.begin(),G.end(),cmp);            //保证字典序最小,因此判断二进制最后一位的大小
        num=0,siz=G.size();
        for(i=0;i<siz;i++)
        for(j=1;j<=n;j++)
        if(G[i]&(1<<(j-1))){
        num++;
        if(num==n)
        printf("%d\n",j);
        else
        printf("%d ",j);
        }
    }
    return 0;
}

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值