题目链接:题目链接
题目分析:
我们发现n的范围很小,可以考虑记忆化搜索或者状态压缩,我们设f[i]表示打掉i状态里所有为1的位所表示的小猪得最小花费;
f[i]=min(f[i],f[i^(i&(G[j][k]))+1];
我们枚举状态i和小猪j,k其中G[][]表示i,j所形成的抛物线所能打掉的小猪的集合,^表示在状态i中除去一个状态也就是说i的状态是由i^(i&G[j][k])转移过来的,i&G[j][k]表示i的状态中被i,j所形成的抛物线所打掉的集合。
最后注意一下浮点情况,设一个EPS就好了;
G[][]需要预处理一下,公式加减消元;
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#define EPS 1e-8
int G[18][18],f[1<<20],T,n,m;
double x[18],y[18];
using namespace std;
int main()
{
scanf("%d",&T);
while(T--)
{
memset(f,0,sizeof(f));
memset(G,0,sizeof(G));
memset(x,0,sizeof(x));
memset(y,0,sizeof(y));
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++) scanf("%lf%lf",&x[i],&y[i]);
int sum=(1<<n)-1;
for(int i=0;i<n;i++)//预处理每两个猪所形成的抛物线,并压缩其对其他猪的影响
{
for(int j=0;j<n;j++)
{
if(i==j) continue ;
double a=(x[j]*y[i]-x[i]*y[j])/(x[i]*x[j]*(x[i]-x[j]));
double b=(x[j]*x[j]*y[i]-x[i]*x[i]*y[j])/(x[i]*x[j]*(x[j]-x[i]));
if(a<=EPS)
{
for(int k=0;k<n;k++)
{
if(fabs(a*x[k]*x[k]+b*x[k]-y[k])<=EPS)
{
G[i][j]|=(1<<(k));
}
}
}
}
}
f[0]=0;
for(int i=1;i<=sum;i++)//枚举每一种可能出现的状态
{
int j,k;
for( j=0;j<n;j++)
{
if(i&(1<<j)) break;//如果这只猪在当前状态里已经被消灭,break;
}
f[i]=f[i^(1<<j)]+1;//更新状态;
for(k=0;k<n;k++)//更新这个猪和其他诸所组成的抛物线所可以达到的状态
{
if(k!=j&&((1<<k)&i))//已经被消灭
f[i]=min(f[i],f[i^(i&G[j][k])]+1);//(i&G[i][j]表示i这个状态中可以被i,j所形成的抛物线打掉的猪),更新
}
}
printf("%d\n",f[sum]);//打掉所有的猪
}
return 0;
}