hdu 3920之状态压缩dp

来源:互联网 发布:linux解压缩gz文件 编辑:程序博客网 时间:2024/05/22 04:45

Clear All of Them I

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 122768/62768 K (Java/Others)
Total Submission(s): 1378    Accepted Submission(s): 461


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
 

题意简述:有一个激光发射点x,y,需要去消灭2*n个敌人,每次发射激光可以消灭2个敌人a,b消耗能量为激光消灭敌人的路径:(x,y)->a->b或者(x,y)->b->a的路径

求消灭所有敌人所需要消耗的最少能量

分析:2*n个敌人,消灭敌人的顺序不能导致消耗的能量不同,很容易想到用状态dp压缩,由于2*n<=20,而2^(20)*(2n)*(2n)达到了上亿的复杂度,所以经过分析和提交果断超时了

继续分析可以发现对于消灭敌人a,b如果(x,y)->a  <  (x,y)->b的路径则肯定是先消灭a再消灭b,所以对于消灭敌人a,则下一个消灭的敌人一定是路径长度大于发射点到a的点

对敌人到达发射点的距离进行从小到大排序,如果消灭敌人j,则下一个消灭的敌人从j+1开始

#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <string>#include <queue>#include <algorithm>#include <map>#include <cmath>#include <iomanip>#define INF 99999999typedef long long LL;using namespace std;const int MAX=(1<<20)+10;int n,sx,sy,num;double dp[MAX];bool mark[MAX];struct Node{int x,y;double dist;bool operator<(const Node &a)const{return dist<a.dist;}}s[22];double cal(int x1,int y1,int x2,int y2){double sum=(x1-x2)*(x1-x2)*1.0+(y1-y2)*(y1-y2)*1.0;return sqrt(sum);}/*double dfs(int i){if(mark[i])return dp[i];mark[i]=true;int j=0;while(i&(1<<j) && j<n)++j;for(int k=j+1;k<n;++k){if(i&(1<<k))continue;dp[i]=min(dp[i],s[j].dist+cal(s[j].x,s[j].y,s[k].x,s[k].y)+dfs(i|(1<<j)|(1<<k)));}return dp[i];}*/void DP(){int bit=1<<n;for(int i=1;i<bit;++i)dp[i]=INF*1.0;for(int i=0;i<bit;++i){if(dp[i] == INF*1.0)continue;int j=0;while(i&(1<<j) && j<n)++j;for(int k=j+1;k<n;++k){if(i&(1<<k))continue;int t=i|(1<<j)|(1<<k);dp[t]=min(dp[t],dp[i]+s[j].dist+cal(s[j].x,s[j].y,s[k].x,s[k].y));} }printf("Case #%d: %.2lf\n",++num,dp[bit-1]);}int main(){int t;scanf("%d",&t);while(t--){scanf("%d%d",&sx,&sy);scanf("%d",&n);n=2*n;for(int i=0;i<n;++i)scanf("%d%d",&s[i].x,&s[i].y),s[i].dist=cal(sx,sy,s[i].x,s[i].y);sort(s,s+n);DP();//int bit=1<<n;//for(int i=0;i<bit;++i)dp[i]=INF*1.0;//dp[bit-1]=0;//memset(mark,false,sizeof mark);//printf("Case #%d: %.2lf\n",++num,dfs(0));}return 0;}



0 0
原创粉丝点击