#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; double x[20],y[20]; const double eps=1e-6; int vis[20],ans,n,m; void dfs(int a,int b) { if(a>n) ans=min(ans,b); else { if(vis[a]) dfs(a+1,b); else { vis[a]=1; for(int i=a+1;i<=n;i++) if(!vis[i]) { double aa=(x[i]*y[a]-x[a]*y[i])/(x[a]*x[i]*x[a]-x[a]*x[i]*x[i]),bb=(x[i]*y[a]*x[i]-x[a]*x[a]*y[i])/(x[a]*x[i]*x[i]-x[a]*x[a]*x[i]); if(aa>=0) continue; for(int j=a+1;j<=n;j++) { double t=fabs(aa*x[j]*x[j]+bb*x[j]-y[j]); if(t<eps) vis[j]=1; } dfs(a+1,b+1); for(int j=a+1;j<=n;j++) { double t=fabs(aa*x[j]*x[j]+bb*x[j]-y[j]); if(t<eps) vis[j]=0; } } dfs(a+1,b+1); vis[a]=0; } } return; } int main() { int t; scanf("%d",&t); while(t--) { ans=20; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%lf%lf",&x[i],&y[i]); memset(vis,0,sizeof(vis)); dfs(1,0); printf("%d\n",ans); } return 0; }
接下来我们考虑提前算出n^2条抛物线,并且用一个2进制数来表示第i位表示以这个抛物线能否打到第i只鸟。然后用f[i]表示达到状态所需的最少抛物线数量。
f[i|zt[j]]=min(f[i]+1);zj[j]表示第j条抛物线对应的二进制数。时间复杂度(T*2^n*n^2)
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; double x[20],y[20]; const double eps=1e-6; int ans,n,m,zt[405],f[1048580]; int main() { int t; scanf("%d",&t); while(t--) { ans=20;int bs=0,xd; memset(zt,0,sizeof(zt)); scanf("%d%d",&n,&m); xd=(1<<n)-1; for(int i=1;i<=n;i++) scanf("%lf%lf",&x[i],&y[i]); for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) if(i!=j) { double aa=(x[i]*y[j]-x[j]*y[i])/(x[j]*x[i]*x[j]-x[j]*x[i]*x[i]),bb=(x[i]*y[j]*x[i]-x[j]*x[j]*y[i])/(x[j]*x[i]*x[i]-x[j]*x[j]*x[i]); if(aa<0) { ++bs; for(int k=1;k<=n;++k) { double t=fabs(aa*x[k]*x[k]+bb*x[k]-y[k]); if(t<eps) zt[bs]+=1<<k-1; } } } memset(f,0x3f,sizeof(f)); f[0]=0; for(int i=0;i<(1<<n);++i) { for(int j=1;j<=bs;++j) f[i|zt[j]]=min(f[i]+1,f[i|zt[j]]); for(int j=1,t=1;j<=n;t=1<<j,++j) f[i|t]=min(f[i]+1,f[i|t]); } printf("%d\n",f[xd]); } return 0; }
现在我们来优化一下这个dp,然每次进行转移的抛物线必须覆盖第一个还未覆盖点(这个用vector记录即可),时间复杂度就被优化到了(T*2^n*n)
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<algorithm> using namespace std; double x[20],y[20]; const double eps=1e-6; int ans,n,m,zt[405],f[262145]; vector<int>fg[20]; int main() { int t; scanf("%d",&t); while(t--) { ans=20;int bs=0,xd; memset(zt,0,sizeof(zt)); scanf("%d%d",&n,&m); xd=(1<<n)-1; for(int i=1;i<=n;i++) scanf("%lf%lf",&x[i],&y[i]),fg[i].clear(); for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) if(i!=j) { double aa=(x[i]*y[j]-x[j]*y[i])/(x[j]*x[i]*x[j]-x[j]*x[i]*x[i]),bb=(x[i]*y[j]*x[i]-x[j]*x[j]*y[i])/(x[j]*x[i]*x[i]-x[j]*x[j]*x[i]); if(aa<0) { ++bs; for(int k=1;k<=n;++k) { double t=fabs(aa*x[k]*x[k]+bb*x[k]-y[k]); if(t<eps) zt[bs]+=1<<k-1,fg[k].push_back(bs); } } } memset(f,0x3f,sizeof(f)); f[0]=0; for(int i=0;i<xd;++i) { int w=1; for(int j=i;j&1;++w,j>>=1); f[i|1<<w-1]=min(f[i|1<<w-1],f[i]+1); int sl=fg[w].size(); for(int j=0;j<sl;++j) f[i|zt[fg[w][j]]]=min(f[i]+1,f[i|zt[fg[w][j]]]); } printf("%d\n",f[xd]); } return 0; }