题意:有 n n n只猪,第 i i i只坐标为 ( x i , y i ) (x_i,y_i) (xi,yi),问最少要用多少形如 y = a x 2 + b x y=ax^2+bx y=ax2+bx的抛物线才能将所有猪打下来,要求这些抛物线都过 ( 0 , 0 ) (0,0) (0,0)点,且 a < 0 a<0 a<0。 ( n < = 18 ) (n<=18) (n<=18)
n的范围如此小,我们考虑状压dp,对于每一对猪
i
,
j
i,j
i,j,我们可以用三个点
(
0
,
0
)
,
(
x
i
,
y
i
)
,
(
x
j
,
y
j
)
(0,0),(x_i,y_i),(x_j,y_j)
(0,0),(xi,yi),(xj,yj)确定一条抛物线,如果该抛物线的
a
<
0
a<0
a<0,就把它留下来,并求出这条抛物线可以打下那些猪。我们将每只猪是否被打下来的
01
01
01状态压缩成十进制数,
d
p
[
i
]
dp[i]
dp[i]表示在状态
i
i
i下最少需要多少条抛物线。我们枚举所有状态,对于每一种状态,我们枚举所有合法的抛物线,转移方程为:
d
p
[
i
∣
s
[
j
]
]
=
m
i
n
(
d
p
[
i
∣
s
[
j
]
]
,
d
p
[
i
]
+
1
)
;
,
s
[
j
]
为
第
j
条
抛
物
线
能
打
下
的
猪
。
dp[i|s[j]]=min(dp[i|s[j]],dp[i]+1);,s[j]为第j条抛物线能打下的猪。
dp[i∣s[j]]=min(dp[i∣s[j]],dp[i]+1);,s[j]为第j条抛物线能打下的猪。
但是可能有些猪不能被已经求出的所有抛物线打下来,因为可能与这些猪形成的所有的抛物线
a
a
a都大于
0
0
0,所以我们还要枚举每一头猪,看一头一头的打是否能更新答案。转移方程为:
d
p
[
i
∣
(
1
<
<
(
j
−
1
)
)
]
=
m
i
n
(
d
p
[
i
∣
(
1
<
<
(
j
−
1
)
)
]
,
d
p
[
i
]
+
1
)
;
dp[i|(1<<(j-1))]=min(dp[i|(1<<(j-1))],dp[i]+1);
dp[i∣(1<<(j−1))]=min(dp[i∣(1<<(j−1))],dp[i]+1);
要注意的地方:在判断一条抛物线能否打下某一头猪时,因为都是double型变量,所以要
if(fabs(a*x[k]*x[k]+b*x[k]-y[k])<=eps)
以下做法可能会出锅QAQ
if(a*x[k]*x[k]+b*x[k]-y[k]==0)
最后的结果就是 d p [ ( 1 < < n ) − 1 ] dp[(1<<n)-1] dp[(1<<n)−1]了。
#include<bits/stdc++.h>
using namespace std;
const double eps=1e-6;
int T,n,m,dp[550000],s[550000],num;
double x[1000],y[1000];
int main()
{
cin>>T;
while(T--)
{
num=0;
memset(x,0,sizeof(x));
memset(y,0,sizeof(y));
memset(s,0,sizeof(s));
memset(dp,0x3f,sizeof(dp));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
scanf("%lf%lf",&x[i],&y[i]);
for(int i=1;i<=n;++i)
for(int j=i+1;j<=n;++j)
{
if(x[i]!=x[j])
{
double a=((x[i]*y[j])-(x[j]*y[i]))/((x[i]*x[j]*x[j])-(x[i]*x[i]*x[j]));
double b=(y[i]/x[i])-(((x[i]*y[j])-(x[j]*y[i]))/((x[j]*x[j])-(x[i]*x[j])));
if(a<0)
{
num++;
for(int k=1;k<=n;++k)
if(fabs(a*x[k]*x[k]+b*x[k]-y[k])<=eps)
s[num]|=(1<<(k-1));
}
}
}
dp[0]=0;
for(int i=0;i<(1<<n);++i)
{
for(int j=1;j<=num;++j)
dp[i|s[j]]=min(dp[i|s[j]],dp[i]+1);//按抛物线打
for(int j=1;j<=n;++j)
dp[i|(1<<(j-1))]=min(dp[i|(1<<(j-1))],dp[i]+1);//只打一头
}
printf("%d\n",dp[(1<<n)-1]);
}
return 0;
}