【NOIP2016】愤怒的小鸟 搜索

题目描述

Kiana 最近沉迷于一款神奇的游戏无法自拔。

简单来说,这款游戏是在一个平面上进行的。

有一架弹弓位于 (0,0)(0,0) 处,每次 Kiana 可以用它向第一象限发射一只红色的小鸟,小鸟们的飞行轨迹均为形如 y=ax^2+bxy=ax2+bx 的曲线,其中 a,ba,b 是Kiana 指定的参数,且必须满足 a < 0a<0,a,ba,b 都是实数。

当小鸟落回地面(即 xx 轴)时,它就会瞬间消失。

在游戏的某个关卡里,平面的第一象限中有 nn 只绿色的小猪,其中第 ii 只小猪所在的坐标为 \left(x_i,y_i \right)(xi,yi)。

如果某只小鸟的飞行轨迹经过了 \left( x_i, y_i \right)(xi,yi),那么第 ii 只小猪就会被消灭掉,同时小鸟将会沿着原先的轨迹继续飞行;

如果一只小鸟的飞行轨迹没有经过 \left( x_i, y_i \right)(xi,yi),那么这只小鸟飞行的全过程就不会对第 ii 只小猪产生任何影响。

例如,若两只小猪分别位于 (1,3)(1,3) 和 (3,3)(3,3),Kiana 可以选择发射一只飞行轨迹为 y=-x^2+4xy=x2+4x 的小鸟,这样两只小猪就会被这只小鸟一起消灭。

而这个游戏的目的,就是通过发射小鸟消灭所有的小猪。

这款神奇游戏的每个关卡对 Kiana来说都很难,所以Kiana还输入了一些神秘的指令,使得自己能更轻松地完成这个游戏。这些指令将在【输入格式】中详述。

假设这款游戏一共有 TT 个关卡,现在 Kiana想知道,对于每一个关卡,至少需要发射多少只小鸟才能消灭所有的小猪。由于她不会算,所以希望由你告诉她。

输入输出格式

输入格式: 

第一行包含一个正整数 T,表示游戏的关卡总数。

下面依次输入这 T 个关卡的信息。每个关卡第一行包含两个非负整数 n,m n,m,分别表示该关卡中的小猪数量和 Kiana 输入的神秘指令类型。接下来的 n行中,第 i行包含两个正实数 xi,yi,表示第 i 只小猪坐标为 (xi,yi)。数据保证同一个关卡中不存在两只坐标完全相同的小猪。

如果 m=0,表示Kiana输入了一个没有任何作用的指令。

如果 m=1,则这个关卡将会满足:至多用 n/3+1⌉ 只小鸟即可消灭所有小猪。

如果 m=2,则这个关卡将会满足:一定存在一种最优解,其中有一只小鸟消灭了至少 n/3⌋ 只小猪。

保证 1n18,0m2,0<xi,yi<10,输入中的实数均保留到小数点后两位。

上文中,符号c⌉ 和 c⌋ 分别表示对 c 向上取整和向下取整,例如:\lceil 2.1 \rceil = \lceil 2.9 \rceil = \lceil 3.0 \rceil = \lfloor 3.0 \rfloor = \lfloor 3.1 \rfloor = \lfloor 3.9 \rfloor = 32.1=2.9=3.0=3.0=3.1=3.9=3。

 

输出格式:

 

对每个关卡依次输出一行答案。

输出的每一行包含一个正整数,表示相应的关卡中,消灭所有小猪最少需要的小鸟数量。

 

输入输出样例

输入样例#1: 
2
2 0
1.00 3.00
3.00 3.00
5 2
1.00 5.00
2.00 8.00
3.00 9.00
4.00 8.00
5.00 5.00
输出样例#1:
1
1
输入样例#2:
3
2 0
1.41 2.00
1.73 3.00
3 0
1.11 1.41
2.34 1.79
2.98 1.49
5 0
2.72 2.72
2.72 3.14
3.14 2.72
3.14 3.14
5.00 5.00
输出样例#2:
2
2
3
输入样例#3: 
1
10 0
7.16 6.28
2.02 0.38
8.33 7.78
7.68 2.09
7.46 7.86
5.77 7.44
8.24 6.72
4.42 5.11
5.42 7.79
8.15 4.99
输出样例#3:
6

说明

【样例解释1】

这组数据中一共有两个关卡。

第一个关卡与【问题描述】中的情形相同,22只小猪分别位于(1.00,3.00)(1.00,3.00)和 (3.00,3.00)(3.00,3.00),只需发射一只飞行轨迹为y = -x^2 + 4xy=x2+4x的小鸟即可消灭它们。

第二个关卡中有55只小猪,但经过观察我们可以发现它们的坐标都在抛物线 y = -x^2 + 6xy=x2+6x上,故Kiana只需要发射一只小鸟即可消灭所有小猪。

【数据范围】

------------------------------------------------------------------

听说这道题要用状压.....但基于现在我能避开DP就尽量避开Dp的策略 我选择爆搜一波(悄悄撒花

其实搜并没有什么思维难度 甚至用不上题目给的m的信息

对于每只猪了,存在两种情况:

1.和之前的某猪连成线 我们可以暴力枚举 算出抛物线的系数 用na[i]和nb[i]记录

2.不和之前的某猪连成线 那么就加入单独成线的行列之中 用 dx[i]和dy[i]记录

每次dfs传入三个信息(now,u,v)// now当前猪 u被安排过了 v各自成一条线

P.S. :当时以为 找之前的猪 和 从单个猪的行列中取出一只猪 暴力会GG 结果居然就这么水过去了????

MARK:

1.请注意哪些数组需要开为double

2.判断两个浮点数相同的方式:做差之后小于某精度

double eps=1e-8;

bool cmp(double a,double b)

{

  return( fabs(a-b)<eps );

}

3.ans的剪枝和更新条件、方式

以下代码

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #define N 50
 7 using namespace std;
 8 struct node
 9 {
10     double x,y;
11 }e[N];
12 int n,m,ans;
13 double na[N],nb[N];
14 double dx[N],dy[N];
15 double eps=1e-8;
16 bool cmp(double a,double b)
17 {
18     return( fabs(a-b)<eps );
19 }
20 void dfs(int now,int u,int v)//now当前猪 u被安排 v各自一条线 
21 {
22     if(u+v>=ans) return;
23     if(now>n)
24     {
25         ans=u+v;
26         return;
27     }
28     bool flag=0;
29     for(int i=1;i<=u;i++)
30         if( cmp(e[now].x*e[now].x*na[i]+e[now].x*nb[i],e[now].y) )//之前在线上
31         {
32             dfs(now+1,u,v);
33             flag=1;
34             break;
35         }
36     if(!flag)
37     {
38         for(int i=1;i<=v;i++)//选择和之前的猪连成一线 
39         {
40             if( cmp(e[now].x,dx[i]) ) continue;
41             double a=(dx[i]*e[now].y-e[now].x*dy[i])/(e[now].x*e[now].x*dx[i]-e[now].x*dx[i]*dx[i]); 
42             double b=(e[now].y-a*e[now].x*e[now].x)/(e[now].x);
43             if(a<0)
44             {
45                 na[u+1]=a; nb[u+1]=b;//记下这条线 
46                 double piu=dx[i],biu=dy[i]; 
47                 for(int j=i;j<=v;j++)//暴力哭了的减单
48                 {
49                      dx[j]=dx[j+1];
50                      dy[j]=dy[j+1];
51                 }
52                 dfs(now+1,u+1,v-1);
53                 for(int j=v;j>=i;j--)//暴力哭了的加单
54                 {
55                      dx[j]=dx[j-1];
56                      dy[j]=dy[j-1];
57                 }
58                 dx[i]=piu; dy[i]=biu;
59             }
60         }
61         //选择不和现在的猪构成一个新线 
62         dx[v+1]=e[now].x;
63         dy[v+1]=e[now].y; 
64         dfs(now+1,u,v+1);
65     }
66 }
67 int main()
68 {
69     int t;
70     scanf("%d",&t);
71     while(t--)
72     {
73         scanf("%d%d",&n,&m);
74         for(int i=1;i<=n;i++)
75             scanf("%lf%lf",&e[i].x,&e[i].y);
76         ans=1000;
77         dfs(1,0,0);
78         printf("%d\n",ans);
79     }
80     return 0;
81 }
82 /*
83 1
84 5 2
85 1.00 5.00
86 2.00 8.00
87 3.00 9.00
88 4.00 8.00
89 5.00 5.00
90 */

 

转载于:https://www.cnblogs.com/kylara/p/9748734.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值