hdu 4385 Moving Bricks (状态压缩dp 2012 Multi-University 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 }
 

 

你可能感兴趣的:(test)