hdu4385(状态压缩dp)

来源:互联网 发布:华为网络盒子怎么样 编辑:程序博客网 时间:2024/04/28 15:12

链接:点击打开链接

题意:有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;}

1 0
原创粉丝点击