题意:已知有 2*n个敌人,用枪射击n 次,每次消灭2个敌人,消耗的能量为自己所在位置到第一个敌人的距离加上第一个敌人到第二个敌人的距离,问消灭
所有敌人所需要消耗的最少能量是多少。
分析:状态DP:
由于每两个敌人消灭的时间不影响答案,所以只需要一维的DP保存所有可能的组合状态即可
转移方程:
dp[i] = min (dp[i], dp[i+(1<<i)+(1<<j)]+dis)
#include<stdio.h> #include<string.h> #include<math.h> #define clr(x)memset(x,0,sizeof(x)) #define INF 0x1f1f1f1f double dp[1<<20]; double dis[150][150]; struct point { double x,y; }p[30],s; double min(double a,double b) { return a<b?a:b; } double Dis(point a,point b) { return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } int main() { int t,n,ca=1; scanf("%d",&t); while(t--) { int i,j,k; scanf("%lf%lf",&s.x,&s.y); scanf("%d",&n); for(i=0;i<2*n;i++) scanf("%lf%lf",&p[i].x,&p[i].y); for(i=0;i<2*n;i++) { dis[i][2*n]=Dis(s,p[i]); for(j=0;j<2*n;j++) dis[i][j]=dis[j][i]=Dis(p[i],p[j]); } int st=(1<<(2*n))-1; for(i=0;i<=st;i++) dp[i]=INF; dp[0]=0; for(i=0;i<=st;i++) if(dp[i]!=INF) { for(j=0;j<2*n;j++) if((i&(1<<j))==0) break; for(k=j+1;k<2*n;k++) { if(i&(1<<k)) continue; double tmp=min(dis[j][2*n],dis[k][2*n]); tmp+=dis[j][k]; int stat=i+(1<<j)+(1<<k); dp[stat]=min(dp[stat],dp[i]+tmp); } } printf("Case #%d: %.2lf\n",ca++,dp[st]); } return 0; }