题目描述
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.
算法思路
1.这一题使用状态压缩是很显然的。
2.我们把解题的步骤分为n步,每一步挑选出两个目标进行射击。我们假设这两个目标为Ai,Aj,那么,我们是否要尝试每一个i,j呢?
3.答案是不需要的,因为我们在选择射击目标的时候,其实选择出来的组合又构成了一个组合关系,比如第一次选择的两个目标完全可以和第二次选择的两个目标调换。因为它们没有先后的关系。
4.所以,知道了这一点之后,我们的算法复杂度降为O(n2)
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
using namespace std;
#define MAXN 11
#define MX 1050000
#define MAX 1e+20
struct CPoint{
double x,y;
}PointList[2*MAXN],st;
int n,cas = 0;
int t;
double dp[MX];
double dis(CPoint s,CPoint t)
{
return sqrt((s.x-t.x)*(s.x-t.x)+(s.y-t.y)*(s.y-t.y));
}
double Dfs(int position)
{
//printf("%d\n",position);
if(dp[position] >= 0)return dp[position];
dp[position] = MAX;
int i,j;
//select two targets
for(i=0;i<=2*n-1;i++){
//printf("%d %d %d\n",position,i,n);
if(position&(1<<i)){
//printf("YES\n");
for(j=i+1;j<=2*n-1;j++){
if(position & (1<<j)){
double dist = dis(PointList[i],PointList[j])+min(dis(st,PointList[i]),dis(st,PointList[j]));
dp[position] = min(dp[position],Dfs(position-(1<<i)-(1<<j))+dist);
}
}
//no need to try all the combinations
break;
}
}
//printf("%d\n",position);
return dp[position];
}
int main()
{
//freopen("input","r",stdin);
int i;
scanf("%d",&t);
while(t--){
cas++;
scanf("%lf %lf",&st.x,&st.y);
scanf("%d",&n);
for(i=0;i<2*n;i++)
scanf("%lf %lf",&PointList[i].x,&PointList[i].y);
for(i=0;i<=(1<<(2*n));i++)
dp[i] = -1.0;
dp[0] = 0;
printf("Case #%d: ",cas);
//solve the problem from the top
printf("%.2f\n",Dfs((1<<(2*n))-1));
}
return 0;
}