LG2831 愤怒的小鸟
题意
分析
看n的范围只有18,考虑状压dp。
用\(f(s)\)表示过集合s中的点所需最小的抛物线数量。
然后枚举点对算抛物线,判断其他点是否在抛物线上来转移。
细节
判断能否构成抛物线只需要判断斜率关系,具体来说是
\[\frac{y_i}{x_i} > \frac{y_j-y_i}{x_j-x_i}
\]
判断三点是否在同一抛物线上,考虑方程
\[\left\{
\begin{array}{}
a x_i^2 + bx_i & = & y_i \\
a x_j^2 + bx_j & = & y_j \\
a x_k^2 + bx_k & = & y_k \\
\end{array}
\right.
\]
有解的条件是矩阵
\[\left[
\begin{matrix}
x_i^2 & x_i & y_i \\
x_j^2 & x_j & y_j \\
x_k^2 & x_k & y_k
\end{matrix}
\right]
\]
线性相关,只需行列式为0。(B君太优秀了。)
代码
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<string>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<complex>
#define rg register
#define il inline
#define co const
#pragma GCC optimize ("O0")
using namespace std;
template<class T> il T read(rg T&x)
{
rg T data=0;
rg int w=1;
rg char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
w=-1;
ch=getchar();
}
while(isdigit(ch))
data=10*data+ch-'0',ch=getchar();
return x=data*w;
}
typedef long long ll;
const int INF=0x7fffffff;
const int MAXN=20;
int n,m,ms;
ll x[MAXN],y[MAXN];
int f[1<<MAXN|7];
il void update(rg co int&x)
{
for(rg int i=0;i<=ms;++i)
{
f[i|x]=min(f[i|x],f[i]+1);
// cerr<<(i|x)<<" f="<<f[i|x]<<" fi+1="<<f[i]+1<<" min="<<min(f[i|x],f[i]+1)<<endl;
}
}
il bool in(rg co int&i,rg co int&j,rg co int&k)
{
rg ll det=0;
det += x[i] * x[i] * x[j] * y[k];
det += x[i] * y[j] * x[k] * x[k];
det += y[i] * x[j] * x[j] * x[k];
det -= y[i] * x[j] * x[k] * x[k];
det -= x[i] * x[j] * x[j] * y[k];
det -= x[i] * x[i] * y[j] * x[k];
return det==0;
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
rg int T;
read(T);
while(T--)
{
memset(f,0x3f,sizeof f);
f[0]=0; // edit 1:the init of f
read(n);read(m);
ms=(1<<n)-1;
for(rg int i=0;i<n;++i)
{
rg double xi,yi;
scanf("%lf %lf",&xi,&yi);
x[i] = ll(100 * xi + 0.5);
y[i] = ll(100 * yi + 0.5);
// cerr<<i<<" x="<<x[i]<<" y="<<y[i]<<endl;
}
for(rg int i=0;i<n;++i)
{
update(1<<i);
for(rg int j=0;j<n;++j)
if(x[j] > x[i] && y[i] * (x[j] - x[i]) > x[i] * (y[j] - y[i]))
{
rg int s=(1<<i)|(1<<j);
for(rg int k=0;k<n;++k)
if(in(i,j,k))
s|=(1<<k);
// cerr<<i<<" "<<j<<" s="<<s<<endl;
update(s);
}
}
/* for(int i=0;i<1<<n;++i)
cerr<<i<<" f="<<f[i]<<endl;*/
printf("%d\n",f[ms]);
}
// fclose(stdin);
// fclose(stdout);
return 0;
}
静渊以有谋,疏通而知事。