hdu 4385 Moving Bricks (状态压缩dp 2012 MultiUniversity Training Contest 9 )

http://acm.hdu.edu.cn/showproblem.php?pid=4385

 状态压缩需要好好理解啊;

又是一道 状态压缩的题 ,一开始觉的和 poj 的一道题有点像 ,特地先做了一下那个题 再回来做的这道题,结果还是没做出来 这到,最后看了 解题报告:

题意:

一个人在搬砖,初始位置在(x0,y0),目的地也是(x0,y0),给你n(n<=20)块砖的位置(xi,yi),规定两点之间时间耗费为欧几里德距离的平方,此人一次可以搬不超过两块砖,

问你最少的时间花费并给出方案.

官方题解:

简单状态DP.

需要注意的是,由于耗费的时间是路长的平方,所以一次性取两点的代价并不一定比分两次取小.

每次从building出发

对于当前状态i和当前未纳入状态的点j

t = i | (1<<j);

dp[t] = dp[i] + dist[n][j] + dist[j][n];

对于未纳入状态t的点k

p = t | (1<<k);

dp[k] = dp[i] + dist[n][j] + dist[j][k] + dist[k][n];

关于取点的输出,可以记录当前状态i的前一状态pre[i],两状态取异或即可.每次出发后会取回1~2点 即(Ai1,Ai2)或Ai1

由于各点的序号是不相同的,只需要比较每次出发取到的较小的序号.

将这些点或点对取其中序号较小的作为关键字按升序排序输出即可.

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cmath>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<set>
  7 #include<map>
  8 #include<queue>
  9 #include<vector>
 10 #include<string>
 11 #define Min(a,b) a<b?a:b
 12 #define Max(a,b) a>b?a:b
 13 #define CL(a,num) memset(a,num,sizeof(a));
 14 #define maxn  30
 15 #define eps  1e-8
 16 #define inf 100000000
 17 #define N  4000000
 18 #define ll   __int64
 19 using namespace std;
 20 struct node
 21 {
 22     int x;
 23     int y;
 24 }a[maxn] ,ans[maxn];
 25 int cmp(node a,node b)
 26 {
 27     return a.x < b.x;
 28 }
 29 int dp[N] ,dis[maxn][maxn],pre[N];
 30 int main()
 31 {
 32     int i,j,n,t,tmp,p,tp,k,x,y;
 33     int cas = 0 ;
 34     //freopen("data.txt","r",stdin);
 35     scanf("%d",&t);
 36     while(t--)
 37     {
 38         scanf("%d%d",&x,&y);
 39         scanf("%d",&n);
 40         a[n].x = x;
 41         a[n].y = y;
 42         for(i = 0;i< n;i++)
 43         {
 44             scanf("%d%d",&a[i].x,&a[i].y);
 45         }
 46         for(i = 0; i <=n;i++)
 47         {
 48             for(j = i+1;j<=n;j++)
 49             {
 50                 dis[i][j] = dis[j][i] = (a[i].x - a[j].x)*(a[i].x - a[j].x) + (a[i].y - a[j].y)* (a[i].y - a[j].y);
 51             }
 52         }
 53         memset(dp,0x3f,sizeof(dp));
 54         dp[0] = 0 ;
 55         int stat = (1<<n) - 1;
 56         for(i = 0 ; i <= stat ;i++)
 57         {
 58             for(j = 0 ; j<n;j++)
 59             {
 60                 if(!(i&(1<<j)))
 61                 {
 62                     tp = i|1<< j;
 63                     tmp = dp[i] + 2*dis[j][n];
 64                     if(dp[tp] > tmp)
 65                     {
 66                         dp[tp] = tmp;
 67                         pre[tp] =  i;
 68                     }
 69 
 70                    for(k = 0 ; k< n;k++)//如果 一次 去两块
 71                    {
 72                        if(!(tp&(1<<k)))
 73                        {
 74                            p = tp|1<<k;
 75                            tmp = dp[i] + dis[j][n] + dis[j][k] + dis[k][n] ;
 76                            if(dp[p] > tmp)
 77                            {
 78                                dp[p] = tmp;
 79                                pre[p] = i;// 注意 这里的状态 是记录 去两块 之前的 i 
 80                            }
 81                        }
 82                    }
 83                 }
 84             }
 85 
 86         }
 87            printf("Case %d:\n",++cas);
 88             printf("%d\n",dp[stat]);
 89             int t = stat;
 90             int num = 0;
 91 
 92             while(t)
 93             {
 94                 bool flag = false ;
 95                 int tmp = t^pre[t];
 96                 ans[num].y = 25 ;//用来记录一次 取两个 个的第二个元素  (25 表示初始化 没有)
 97                 for(i = 0 ; i < n;i++)
 98                 {
 99                     if((tmp>>i)&1)
100                     {
101                         if(!flag)
102                         {
103                             ans[num].x = i;
104                             flag = true ;
105                         }
106                         else  ans[num].y = i;
107                     }
108                 }
109 
110                 t = pre[t];
111                 num ++;
112             }
113 
114             sort(ans,ans+num,cmp);
115 
116 
117             for(i = 0 ; i< num;i++)
118             {
119                 if(i == 0)printf("%d",ans[i].x + 1);
120                 else printf(" %d",ans[i].x + 1);
121 
122                 if(ans[i].y < 25) printf(" %d",ans[i].y + 1) ;
123             }
124             puts("");
125 
126 
127 
128 
129     }
130 }
 

 

原文地址:https://www.cnblogs.com/acSzz/p/2651513.html