UOJ265 NOIP2016 day2 T3 愤怒的小鸟
原题地址:http://uoj.ac/problem/265
题意:
有一架弹弓位于 (0,0)(0,0) 处,每次 Kiana 可以用它向第一象限发射一只红色的小鸟,小鸟们的飞行轨迹均为形如 y=ax2+bxy=ax2+bx 的曲线,其中 a,ba,b 是 Kiana 指定的参数,且必须满足 a<0a<0,a,ba,b 都是实数。
当小鸟落回地面(即 xx 轴)时,它就会瞬间消失。
在游戏的某个关卡里,平面的第一象限中有 nn 只绿色的小猪,其中第 ii 只小猪所在的坐标为 (xi,yi)(xi,yi)。
如果某只小鸟的飞行轨迹经过了 (xi,yi)(xi,yi),那么第 ii 只小猪就会被消灭掉,同时小鸟将会沿着原先的轨迹继续飞行;
如果一只小鸟的飞行轨迹没有经过 (xi,yi)(xi,yi),那么这只小鸟飞行的全过程就不会对第 ii 只小猪产生任何影响。
例如,若两只小猪分别位于 (1,3)(1,3) 和 (3,3)(3,3),Kiana 可以选择发射一只飞行轨迹为 y=−x2+4xy=−x2+4x 的小鸟,这样两只小猪就会被这只小鸟一起消灭。
而这个游戏的目的,就是通过发射小鸟消灭所有的小猪。
一共有T组数据,对于每组数据,至少需要发射多少只小鸟才能消灭所有的小猪。
数据范围
保证 1≤n≤18,0≤ m≤2,0< xi,yi< 10,输入中的实数均保留到小数点后两位。
题解:
n^3预处理每两只猪所在抛物线可以射到的猪
枚举猪i,j f[s]=min(f[s|t[i][j]])+1
比较懒,写的记忆化搜索。
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=20;
const double EPS=1e-10;
int T,n,m,t[N][N],f[1<<N];
int inf;
double X[N],Y[N];
int sign(double x)
{
if(fabs(x)<EPS) return 0;
else return x<0?-1:1;
}
bool solve(double x1,double y1,double x2,double y2,double &a,double &b)
{
double d=(x2/x1)*y1-y2;
a=d/(x1*x2-x2*x2);
b=(y1-x1*x1*a)/x1;
if(sign(a)>=0) return 0;
return 1;
}
int dp(int state)
{
if(f[state]!=inf) return f[state];
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)
{
if((state|t[i][j])==state||!t[i][j]) continue;
f[state]=min(f[state],dp(state|t[i][j])+1);
}
for(int i=0;i<n;i++)
{
if((state|(1<<i))==state) continue;
f[state]=min(f[state],dp(state|(1<<i))+1);
}
return f[state];
}
int main()
{
scanf("%d",&T);
while(T--)
{
memset(t,0,sizeof(t));
memset(f,60,sizeof(f));
inf=f[0];
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
{
scanf("%lf%lf",&X[i],&Y[i]);
}
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)
{
double a,b;
if(solve(X[i],Y[i],X[j],Y[j],a,b))
{
t[i][j]=t[i][j]|(1<<i);
t[i][j]=t[i][j]|(1<<j);
for(int k=0;k<n;k++)
{
if(k==i||k==j) continue;
if(sign(a*X[k]*X[k]+b*X[k]-Y[k])==0)
t[i][j]=t[i][j]|(1<<k);
}
}
}
int top=(1<<n)-1;
f[top]=0;
printf("%d\n",dp(0));
}
return 0;
}