【题目描述】
Kiana 最近沉迷于一款神奇的游戏无法自拔。
简单来说,这款游戏是在一个平面上进行的。
有一架弹弓位于
当小鸟落回地面(即
在游戏的某个关卡里,平面的第一象限中有
如果某只小鸟的飞行轨迹经过了
如果一只小鸟的飞行轨迹没有经过
例如,若两只小猪分别位于
而这个游戏的目的,就是通过发射小鸟消灭所有的小猪。
这款神奇游戏的每个关卡对 Kiana 来说都很难,所以 Kiana 还输入了一些神秘的指令,使得自己能更轻松地完成这个游戏。这些指令将在【输入格式】中详述。
假设这款游戏一共有
输入
从标准输入读入数据。
第一行包含一个正整数
下面依次输入这
如果
如果
如果
保证
上文中,符号
输出
输出到标准输出。
对每个关卡依次输出一行答案。
输出的每一行包含一个正整数,表示相应的关卡中,消灭所有小猪最少需要的小鸟数量。
样例一
input
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
output
1
1
explanation
这组数据中一共有两个关卡。
第一个关卡与问题描述中的情形相同,2 只小猪分别位于
第二个关卡中有 5 只小猪,但经过观察我们可以发现它们的坐标都在抛物线
样例二
input
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
output
2
2
3
样例三
input
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
output
6
限制与约定
数据的一些特殊规定如下表:
时间限制:2s
空间限制:512MB
【解题分析】
n比较小,所以可以考虑状压DP或DFS,这里考虑DP。
由于抛物线中的一点已经确定为原点,所以根据三点(不完全hehe)确定一条抛物线,我们可以枚举两个点,然后判断抛物线是否合法(怎么求抛物线看代码,或者自己推,不难)。如果合法,求这条抛物线可以达到哪些点(当然也是用二进制求),然后就直接推,由于上一状态不好找,可以考虑从这一状态推出去。转移方程……略,因为连我这种蒟蒻都觉得很简单。
复杂度:
时间:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int tst,n,m,g[20][20],f[1<<19];
struct data{
double x,y;
bool operator < (const data b)const{
return x<b.x||(x==b.x&&y<=b.y);
}
}a[20];
int fcmp(const double x,const double y){if (fabs(x-y)<1e-10) return 0; return (x>y)?1:-1;}
int main()
{
freopen("angrybirds.in","r",stdin);
freopen("angrybirds.out","w",stdout);
scanf("%d",&tst);
while (tst--){
scanf("%d%d",&n,&m); m=(1<<n)-1; for (int i=0;i<n;i++) scanf("%lf%lf",&a[i].x,&a[i].y);
sort(a,a+n); memset(g,0,sizeof(g));
for (int i=0;i<n-1;i++)
for (int j=i+1;j<n;j++)
if (fcmp(a[i].x,a[j].x)){
double A,B,xa=a[i].x,xb=a[j].x,ya=a[i].y,yb=a[j].y; A=(ya*xb-yb*xa)/(xa*xb*(xa-xb));
if (fcmp(A,0)>=0) continue; B=(ya-A*xa*xa)/xa; if (fcmp(B,0)<=0) continue;
for (int k=0;k<n;k++) if (!fcmp(a[k].x*a[k].x*A+a[k].x*B,a[k].y)) g[i][j]|=(1<<k);
}
memset(f,63,sizeof(f)); f[0]=0;
for (int s=0;s<m;s++)
for (int i=0;i<n;i++)
if (!(s&(1<<i))){
f[s|(1<<i)]=min(f[s|(1<<i)],f[s]+1);
for (int j=i+1;j<n;j++)
f[s|g[i][j]]=min(f[s|g[i][j]],f[s]+1);
}
printf("%d\n",f[m]);
}
return 0;
}