HDU3920
来源:互联网 发布:淘宝售假会怎么样 编辑:程序博客网 时间:2024/06/08 20:12
HDU3920 Clear All of Them I
现在你在一个大地图上,给出你所在的坐标(x,y),然后给出2*n个敌人的坐标,要你消灭这2*n个敌人.你手上有一把激光枪,每次射击你都可以任意选择两个目标,激光先从你的位置到第一个目标,然后再从第一个目标到第二个目标的位置,这样就消灭了这两个目标,激光枪消耗的能量是它总共走过的距离.
你可以选择先攻击哪个目标.
你的位置不可以变.
每个目标只能给攻击一次,所以你需要打n枪.
每个目标的位置唯一.
现在要求你消灭这2*n个目标所需要的最小能量值.
输入:首先是一个T ( T <= 100 ),表示实例个数.对于每个实例,第一行是两个整数(x,y)表示你的位置,第二行是一个n(1 <= n <= 10),表示这里有2*n个敌人,接下来2*n行是每行两个整数,表示敌人的坐标.所有整数都是在[-1000,1000]范围内.
输出:以Case #i: 6.00格式输出最小能量,保留两位小数.
分析:令d[S]表示消灭完了集合S中的敌人(成对出现)后,所需要的最小能量.
d[S+{i,j}]= min{ d[S]+min_value(i,j) } min_value(I,j)表示消灭i和j所需要的最少能量.
复杂度分析:n<=10,d[S]的个数为100w,然后每次选i和j需要400,共100个实例,则就是400亿计算次.
这么做显然超时.
结果正确但超时的代码:
#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>using namespace std;doubled[1<<22];boolvis[1<<22];struct point{ double x,y;};point man;point enemy[20];int n;double length[25][25];bool vis1[25][25];double dist(inti,int j)//返回从起点到i,j的最短距离{ if(vis1[i][j])return length[i][j]; point a = enemy[i], b = enemy[j],c=man; double len = sqrt( (a.x-b.x)*(a.x-b.x) +(a.y-b.y)*(a.y-b.y) );//i与j的距离 double len1 = sqrt( (a.x-c.x)*(a.x-c.x) +(a.y-c.y)*(a.y-c.y) );//起点与i的距离 double len2 = sqrt( (b.x-c.x)*(b.x-c.x) +(b.y-c.y)*(b.y-c.y) );//起点与j的距离 length[i][j] = length[j][i] = min( len+len1, len+len2 ); vis1[i][j]=vis1[j][i] =true; return length[i][j];}int main(){ int T; while(scanf("%d",&T)==1&&T) { for(int kase = 1;kase<=T;kase++) { scanf("%lf%lf",&man.x,&man.y); scanf("%d",&n); for(int i=0;i<2*n;i++) scanf("%lf%lf",&enemy[i].x,&enemy[i].y); memset(vis1,0,sizeof(vis1)); memset(vis,0,sizeof(vis)); vis[0]=true; d[0]=0.0;//初始为0 for(int S=0;S<(1<<(2*n));S++)if(vis[S])//集合S有效 { for(int i=0;i<2*n;i++)if( !(S&(1<<i) ) )//S中不包含i { /*可优化*/for(int j=i+1;j<2*n;j++)if( !( S&(1<<j) ) )//S中不包含j { if(!vis[S|(1<<i)|(1<<j)] ) d[S|(1<<i)|(1<<j)] = d[S]+dist(i,j); else d[S|(1<<i)|(1<<j)] = min( d[S|(1<<i)|(1<<j)] ,d[S]+dist(i,j) ); vis[S|(1<<i)|(1<<j)] = true; } } } printf("Case #%d:%.2lf\n",kase,d[(1<<(2*n))-1]); } } return 0;}
现在换一种解法.用记忆化搜索来算(可以去除很多无用的状态),然后用状态转移方程:
d[S] = min{ d[S-{i,j}]+min_value(i,j) } min_value(i,j)注意i是S中的最低位1,而j是S中的任意一个(但j>i).这里不再是随便选两个i和j了.因为集合S你无论如何其中的最低位i都是要和一个j进行配对了,而且(i,j)在第几被射击是没影响的,所以如果d[S]的最小值确实是由d[S-{i,j}]和d[{i,j}]构成的话,那么先把(i,j)分离出来,再计算d[S-{i,j}]同样是可以得到最小值的.
AC代码:203ms
#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<map>using namespace std;double d[1<<22];bool vis[1<<22];struct point{ double x,y;};point man;point enemy[20];int n;double length[25][25];bool vis1[25][25];map<int ,int > m;double dist(int i,int j)//返回从 起点到i再到j 或 起点到j再到i 的最短距离{ if(vis1[i][j])return length[i][j];//记忆化 point a = enemy[i], b = enemy[j],c=man; double len = sqrt( (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) );//i与j的距离 double len1 = sqrt( (a.x-c.x)*(a.x-c.x) + (a.y-c.y)*(a.y-c.y) );//起点与i的距离 double len2 = sqrt( (b.x-c.x)*(b.x-c.x) + (b.y-c.y)*(b.y-c.y) );//起点与j的距离 length[i][j] = length[j][i] = min( len+len1 , len+len2 ); vis1[i][j]=vis1[j][i] =true; return length[i][j];}double dp(int S)//记忆化搜索DP{ if(vis[S])return d[S]; vis[S]=true; double &ans = d[S]; ans=-1.0; int lowbit = S&(-S);//S二进制形式最低位的i对应的值 int i = m[lowbit]; for(int j=i+1;j<2*n;j++)if(S&(1<<j))//j在S中,且j的位比i的位高 { if(ans<0) ans = dp(S^(lowbit)^(1<<j) ) + dist(i,j) ; else ans = min(ans, dp(S^(lowbit)^(1<<j)) + dist(i,j) ); } return ans;}int main(){ int temp=1; for(int i=0;i<=20;i++) { m[temp]=i; temp *=2; } int T; while(scanf("%d",&T)==1&&T) { for(int kase = 1;kase<=T;kase++) { scanf("%lf %lf",&man.x,&man.y); scanf("%d",&n); for(int i=0;i<2*n;i++) scanf("%lf %lf",&enemy[i].x,&enemy[i].y); memset(vis1,0,sizeof(vis1));//用于标记dist[i][j]的 memset(vis,0,sizeof(vis));//用于标记dp的 vis[0]=true; d[0]=0.0;//初始为0 printf("Case #%d: %.2lf\n",kase,dp( (1<<(2*n))-1 ) ); } } return 0;}
- HDU3920
- hdu3920(状压dp)
- hdu3920(壮压DP)
- hdu3920 状态压缩~最优值
- HDU3920 状压DP+优化+记忆化搜索
- hdu3920 Clear All of Them I
- HDU3920:Clear All of Them I(状态压缩)
- Codeforces Round #232 (Div. 2)
- Hadoop: the definitive guide 第三版 拾遗 第三章 之查看文件及正则表达式
- 一个App调用另一个App的Activity
- 幸福是自己的,别看他人
- ASCII码对照表
- HDU3920
- Hadoop: the definitive guide 第三版 拾遗 第四章 之CompressionCodec
- C/C++中字符串与数字相互转换
- ASP.NET中Server对象的介绍
- MYSQL为新用户分配权限
- Hadoop: the definitive guide 第三版 拾遗 第四章 之hadoop本地库
- CreateTable - sqlite
- 人生里的酸甜苦辣,缺了哪样都是遗憾
- (八)IO库