状态压缩+dp;
我们用f[s]表示消灭掉s这个状态的猪最少需要几次。
预处理出attack[i][j],表示穿过i,j这两只小猪的曲线能打下的猪。
那么f[s]=min(f[s],f[s^(s&attack[j][k])]);
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define LL long long
#define DO double
#define P(x) (x)*(x)
using namespace std;
const DO res=1e-6;
const int N=(1<<18);
int attack[20][20];
int f[N+10],Q,n,m;
DO X[20],Y[20];
DO work(int i,int j)//解方程
{
DO x=X[i],y=Y[i],xx=X[j],yy=Y[j];
DO s;
s=(xx*y-x*yy)/(x*xx*(x-xx));
return s;
}
int main()
{
scanf("%d",&Q);
while(Q--)
{
memset(attack,0,sizeof(attack));
//memset(f,127/3,sizeof(f));
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=0;j<n;j++)
if(i!=j)
{
int s=0;
DO a=work(i,j);
DO b=(Y[i]-X[i]*X[i]*a)/X[i];//解方程
//printf("%lf %lf\n",a,b);
if(a<=res)
for(int k=0;k<n;k++)
{
if(fabs(a*P(X[k])+b*X[k]-Y[k])<=res)
s=s|(1<<k);
}
attack[i][j]=s;
}//预处理
f[0]=0;
int i,j;
for(i=1;i<(1<<n);i++)
{
for(j=0;j<n;j++)
if((1<<j)&i) break;//找到i状态下第一个活着的猪
f[i]=f[i^(1<<j)]+1;
for(int k=0;k<n;k++)
if(k!=j&&(1<<k)&i)
{
f[i]=min(f[i],f[i^(i&attack[j][k])]+1);
}
}
printf("%d\n",f[(1<<n)-1]);
}
//cout<<N;
return 0;
}