Description
Input
Output
solution
这道题可以用状压DP来做,首先,我们先预处理出任意两个点所推出的抛物线,在找出这个抛物线所经过的点数,用一个二进制数来表示,例如经过i,j两点的抛物线经过了1,5,8点,就是g[i][j]=10001001。
然后再设f[i]为状态为i时所需要的最少抛物线的数量。此时可推出方程式f[i|g[j][l]]=min(f[i]+1,f[i|g[j][l]]),此时要注意,我们还要判断一下,可能有些点需要一个点用一条抛物线,所以在此从1枚举到n,就是f[i|(1<<j-1)]=min(f[i|(1<<j-1)],f[i]+1)。
code
#include<bits/stdc++.h>
#define rg register int
#define con continue
using namespace std;
int T,n,m,g[20][20],f[1000005];
double x[20],y[20],a,b,t;
bool pd(double x,double y){
return abs(x-y)<(1e-6);
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(rg i=1;i<=n;i++) scanf("%lf%lf",&x[i],&y[i]);
for(rg i=1;i<=n;i++) for(rg j=i+1;j<=n;j++) g[i][j]=0;
for(rg i=1;i<=n;i++)
{
for(rg j=i+1;j<=n;j++)
{
t=a=b=0;
if(x[i]==x[j]) con;
a=(y[j]/x[j]-y[i]/x[i])*1.0/(x[j]-x[i])*1.0;
if(a>=0) con;//a要是负数
b=y[i]/x[i]*1.0-a*x[i]*1.0;
//确定一条抛物线,y=axx+bx
for(rg l=1;l<=n;l++)
if(pd(y[l]/x[l],a*x[l]+b)) t+=(1<<(l-1));
g[i][j]=t;
}
}
//把所有可能的抛物线求出来
for(rg i=1;i<=(1<<n);i++) f[i]=99999;
f[0]=0;
for(rg i=0;i<(1<<n);i++)
{
for(rg j=1;j<=n;j++)
{
if(!(i&(1<<(j-1))))
{
for(rg l=j+1;l<=n;l++)
{
f[i|g[j][l]]=min(f[i|g[j][l]],f[i]+1);
}
f[i|(1<<j-1)]=min(f[i|(1<<j-1)],f[i]+1);
}
}
}
//枚举所有抛物线的可能
printf("%d\n",f[(1<<n)-1]);
}
return 0;
}