题目
思路
由我弱弱的数学知识可知,三点确定一抛物线,所以尽量让一只鸟经过俩猪(还有一个确定抛物线的点在原点)(除非求出的抛物线 a > 0 a>0 a>0),枚举每两头猪,求出经过这俩猪和原点的抛物线,并看看是否有其他猪在这条抛物线上,最后得到一堆抛物线(当然要包括只经过一头猪的),用这些抛物线经过的猪做状压dp(状压dp部分应该是这题最简单的部分了,不会的看下面的方程)
附上dp方程 f [ S ∣ v [ i ] ] = m i n ( f [ S ∣ v [ i ] ] , f [ S ] + 1 ) ; f[S|v[i]]=min(f[S|v[i]],f[S]+1); f[S∣v[i]]=min(f[S∣v[i]],f[S]+1);
别说不会求抛物线
由于 y [ i ] = a x [ i ] 2 + b [ i ] 且 y [ j ] = a x [ j ] 2 + b x [ j ] y[i]=ax[i]^2+b[i] 且 y[j]=ax[j]^2+bx[j] y[i]=ax[i]2+b[i]且y[j]=ax[j]2+bx[j]加减消元(初中生必备技能),可得 a = x [ j ] y [ i ] − x [ i ] y [ j ] x [ i ] x [ j ] ( x [ i ] − x [ j ] ) a={x[j]y[i]-x[i]y[j] \over x[i]x[j](x[i]-x[j])} a=x[i]x[j](x[i]−x[j])x[j]y[i]−x[i]y[j] b = x [ j ] 2 y [ i ] − x [ i ] 2 y [ j ] x [ i ] x [ j ] ( x [ j ] − x [ i ] ) b={x[j]^2y[i]-x[i]^2y[j] \over x[i]x[j](x[j]-x[i])} b=x[i]x[j](x[j]−x[i])x[j]2y[i]−x[i]2y[j]
代码
#include<bits/stdc++.h>
using namespace std;
#define cl(x) memset(x,0,sizeof(x))
#define inf 2222
typedef double dd;
const int maxn=20;
int n,m;
dd x[maxn],y[maxn];
bool bo[maxn][maxn];
int s[maxn][maxn];
int f[(1<<20)];
void init();
int p=0;
int v[maxn*maxn];
void pre(){
dd a,b;p=0;
cl(s);cl(bo);
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++)if(!bo[i][j]){
a=(y[i]*x[j]-y[j]*x[i])/(x[i]*x[j]*(x[i]-x[j]));
b=(y[i]*x[j]*x[j]-y[j]*x[i]*x[i])/(x[i]*x[j]*(x[j]-x[i]));
if(a>=0){bo[i][j]=1;continue;}
s[i][j]|=1<<(i-1);
s[i][j]|=1<<(j-1);
for(int k=j+1;k<=n;k++)
if(y[k]==a*x[k]*x[k]+b*x[k])
s[i][j]|=1<<(k-1),bo[j][k]=1;
v[++p]=s[i][j];
}
for(int i=1;i<=n;i++)v[++p]=1<<(i-1);
return ;
}
void dp(){
for(int i=0;i<(1<<n);i++)f[i]=inf;
f[0]=0;
for(int i=1;i<=p;i++)
for(int S=0;S<(1<<n);S++)
f[S|v[i]]=min(f[S|v[i]],f[S]+1);
printf("%d\n",f[(1<<n)-1]);
return ;
}
int main(){
// freopen("in","r",stdin);freopen("1.out","w",stdout);
int T;
scanf("%d",&T);
while(T--){
init();
pre();
dp();
}
return 0;
}
void init(){
cl(bo);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%lf%lf",&x[i],&y[i]);
return ;
}