hdu 3920之状态压缩dp

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
  
  
2 0 0 1 6 0 3 0 0 0 2 1 0 2 1 -1 0 -2 0
 

Sample Output
  
  
Case #1: 6.00 Case #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 99999999
typedef 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值