HDU Clear All of Them I(状态压缩+DP+记忆搜索)

来源:互联网 发布:中草药软件 编辑:程序博客网 时间:2024/06/11 02:13
Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 122768/62768 K (Java/Others)
Total Submission(s): 1556    Accepted Submission(s): 509


Problem Description
Acmers have been the Earth Protector against the evil enemy for a long time, now it’s your turn to protect our home.
  There are 2 * n enemies in the map. Your task is to clear all of them with your super laser gun at the fixed position (x, y).
  For each laser shot, your laser beam can reflect 1 times (must be 1 times), which means it can kill 2 enemies at one time. And the energy this shot costs is the total length of the laser path.
  For example, if you are at (0, 0), and use one laser shot kills the 2 enemies in the order of (3, 4), (6, 0), then the energy this shot costs is 5.0 + 5.0 = 10. 00.
  Since there are 2 * n enemies, you have to shot n times to clear all of them. For each shot, it is you that select two existed enemies and decide the reflect order.
  Now, telling you your position and the 2n enemies’ position, to save the energy, can you tell me how much energy you need at least to clear all of them?
  Note that:
   > Each enemy can only be attacked once.
   > All the positions will be unique.
   > You must attack 2 different enemies in one shot.
   > You can’t change your position.
 

Input
The first line contains a single positive integer T( T <= 100 ), indicates the number of test cases.
For each case:
  There are 2 integers x and y in the first line, which means your position.
  The second line is an integer n(1 <= n <= 10), denote there are 2n enemies.
  Then there following 2n lines, each line have 2 integers denote the position of an enemy.
  
  All the position integers are between -1000 and 1000.
 

Output
For each test case: output the case number as shown and then print a decimal v, which is the energy you need at least to clear all of them (round to 2 decimal places).
 

Sample Input
20 016 03 00 021 02 1-1 0-2 0
 



Sample Output
Case #1: 6.00Case #2: 4.41

第一次写的状态压缩的题目,首先这个题目有贪心性质。说明如下:假设当我们以最小代价消灭完全部敌人的状态是S,从S中去除两个同一次消灭的敌人,剩下的状态必定也是最小的,可以反证法证明。现在假设一直退回到初始状态,还剩三点O,A,B。因为AB之间的距离是固定的,所以要想三点连线距离最小肯定要从OA,OB中选最小的。利用贪心可以优化程序。

题目中的状态转移过程:当前状态中随便去除任意两点可以得到上一个状态,从中选最小代价的,复杂度是20*20*2^20,需要记忆化搜索还有上面说的贪心性质降低复杂度。

程序中对点按照距离原点的距离排序,利用贪心,去掉了一个for循环。


#include <iostream>#include <cmath>#include <algorithm>using namespace std;typedef struct node{int x;int y;void input(){scanf("%d%d",&x,&y);}}Point;Point st,pt[21];int n;double dp[1<<21];double dis[21][21];double min(double a,double b){return a<b?a:b;}double eval_dis(Point a,Point b){double x = (a.x-b.x)*1.0;double y = (a.y-b.y)*1.0;return sqrt(x*x+y*y);}bool cmp(Point a,Point b){return eval_dis(a,st) < eval_dis(b,st);}double Dp(int state){if(dp[state] != 0x7fffffff)return dp[state];if(state == 0) dp[0] = 0.0;//初始状态else{int i = 0;for(i = 0;i < 20; i++)//这里用到了贪心思想,即选最近的点 if((1<<i) & state) break;for(int j = i+1;j < 2*n; j++){if(((1<<j)&state)){dp[state] = min(Dp(state-(1<<j)-(1<<i))+dis[i][j],dp[state]); }}}return dp[state];}int main(){int T,ca=0;      scanf("%d",&T);      while(T--)      {         ca++;   st.input();        scanf("%d",&n);          for(int i=0;i<2*n;i++)          {  pt[i].input();        }          sort(pt,pt+2*n,cmp);          for(i=0;i<2*n;i++){            for(int j=i+1;j<2*n;j++){                  dis[i][j] = eval_dis(pt[i],st)+eval_dis(pt[i],pt[j]);  }}printf("Case #%d: ",ca);          for(i=0;i<(1<<2*n);i++)              dp[i] = 0x7fffffff;          printf("%.2f\n",Dp((1<<(2*n))-1));    }return 0;}



Sample Output
Case #1: 6.00Case #2: 4.41
0 0
原创粉丝点击