题目链接
题目:愤怒的小鸟
思路过程
数据范围非常小,\(n\leq 18\),可以考虑指数级时间复杂度的算法。
借鉴曼哈顿路径的状压dp算法,可以设计出状态:\(f(i)\)表示状态为\(i\)时用鸟最小数。
状态转移很好想,预处理一下可以做到\(O(n^2)\)转移
时间复杂度\(O(2^n n^2)\)
完整代码
#include <bits/stdc++.h>
using namespace std;
const int N=18,INF=0x3f3f3f3f;
const double eps=1e-8;
int T,n,m;
double x[N],y[N];
int f[1<<N],p[N][N];
double xx,yy;
void calc(int i,int j) {
double a,b,c,d,e,f;
a=x[i]*x[i],b=x[i],c=y[i];
d=x[j]*x[j],e=x[j],f=y[j];
xx=(e*c-f*b)/(a*e-d*b);
yy=(d*c-f*a)/(d*b-e*a);
}
int main() {
scanf("%d",&T);
while(T--) {
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
scanf("%lf%lf",&x[i],&y[i]);
memset(p,0,sizeof(p));
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++) {
calc(i,j);
if(xx>=0)
continue;
for(int k=0;k<n;k++)
if(abs(y[k]-xx*x[k]*x[k]-yy*x[k])<eps)
p[i][j]|=(1<<k);
}
memset(f,0x3f,sizeof(f));
f[0]=0;
int bound=(1<<n)-1;
for(int i=0;i<=bound;i++) {
if(f[i]==INF)
continue;
for(int j=0;j<n;j++) {
if(i>>j&1)
continue;
f[i|(1<<j)]=min(f[i|(1<<j)],f[i]+1);
for(int k=j+1;k<n;k++) {
if(i>>k&1 or !p[j][k])
continue;
int nxt=i|p[j][k];
f[nxt]=min(f[nxt],f[i]+1);
}
}
}
int ans=f[bound];
for(int i=0;i<n;i++)
ans=min(ans,f[bound^(1<<i)]+1);
printf("%d\n",ans);
}
return 0;
}