题目传送门
本题是一道很明显的状压DP,麻烦的是浮点数的处理和抛物线的计算,这里讲一些注意事项:
一.浮点数判相等:
二.抛物线的判断:
题目中的抛物线有两个未知数,在正常情况下,每两点便可确定一条抛物线,但以下情况除外:
1.两点所在的直线经过原点
2.两点横坐标相等
3.a < 0
做法:
1、N3预处理出所有抛物线,及其能经过的点。
2、转移。
其中还有许多优化,这里我用的是最暴力的方法。
注:本题可用随机化。
#include<cstdio>
#include<algorithm>
#include<cstring>
int para[650];
int tot;
#define inf 1000001
int min(int x,int y)
{
return x<y?x:y;
}
double Mx(double x,double y)
{
return x>y?x:y;
}
double abs(double x)
{
return x>0?x:-x;
}
int dp[1<<19];
double X[21],Y[21];
#define eps 1e-9
bool Be(double x,double y)
{
if(abs(x-y)<=eps*Mx(abs(x),abs(y)))
return true;
else
return false;
}int wuxian[600],jzw=0;
void init()
{
for(int i=0;i<=18;i++) X[i]=Y[i]=0;
for(int i=0;i<=(1<<19)-1;i++)
dp[i]=inf;
dp[0]=0;
jzw=tot=0;
for(int i=1;i<=400;i++)para[i] = 0;
}
double geta(double x1,double y1,double x2,double y2)
{
return (y1*x2-y2*x1)/(x1*x1*x2-x2*x2*x1);
}
double getb(double x1,double y1,double x2,double y2)
{
return (y1*x2*x2-y2*x1*x1)/(x1*x2*x2-x2*x1*x1);
}
double getk(double x1,double y1,double x2,double y2)
{
if(Be(x1,x2)) return inf;
return (y1-y2)/(x1-x2);
}
bool delta(double x1,double y1,double x2,double y2)
{
if(x1==x2) return 0 ;
double k=getk(x1,y1,x2,y2);
double b=y1-k*x1;
if(Be(b,0))
return 1;
if(Be(b,eps))
return 1;
return 0;
}
void build_dp(int n)
{
for(int i=0;i<n;i++)
{
double x1 = X[i+1];
double y1 = Y[i+1];
dp[1<<i] = 1;
// printf("%f %f",x1,y1);
for(int j=0;j<n;j++)
{
double x2 = X[j+1];
double y2 = Y[j+1];
if(x1==x2) continue;
double a = geta(x1,y1,x2,y2);
double b = getb(x1,y1,x2,y2);
// printf("%f ",a);
if(a>0 || delta(x1,y1,x2,y2)) continue ;
dp[(1<<j)|(1<<i)] = 1;
int sta=(1<<j)|(1<<i);
for(int k=0;k<n;k++)
{
double x3 = X[k+1];
double y3 = Y[k+1];
dp[1<<k] = 1;
double yy = a*x3*x3+b*x3;
if(Be(yy,y3))
{
sta|=1<<k;
dp[sta]=1;
}
}
}
}
}
void build_para(int n)
{
for(int i=1;i<=(1<<n)-1;i++)
{
if(dp[i]==1) para[++tot] = i;
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
init();
for(int i=1;i<=n;i++)
scanf("%lf%lf",&X[i],&Y[i]);
build_dp(n);
build_para(n);
// for(int i=1;i<=tot;i++) printf("%d ",para[i]);
// for(int i=1;i<=tot;i++) printf("%d ",para[i]);
for(int i=1;i<=tot;i++)
{
int hit = para[i];
for(int j=0;j<=(1<<n)-1;j++)
dp[j|hit] = min(dp[j|hit],dp[j]+1);
}
printf("%d
",dp[(1<<(n))-1]);
}
}