luogu P2831 [NOIP2016 提高组] 愤怒的小鸟

题面传送门
数据这么小显然状压dp
考虑状压\(dp_i\)表示打掉的集合为\(i\)时最少抛物线条数。
预处理\(f_{i,j}\)表示过\(i\)点和\(j\)点的抛物线经过的点的集合。
但是这样的转移是\(O(T2^nn^2)\)的。
考虑怎么优化。
很明显我们的\(dp\)转移是无序的。将其变成有序即先打最小的点则可优化掉一个\(n\)变为\(O(T2^nn)\)
代码实现:

#include<cstdio>
#include<cstring>
#define abs(x) ((x)>0?(x):-(x))
#define min(a,b) ((a)<(b)?(a):(b))
#define eps 1e-6
using namespace std;
int n,m,dp[1000039],g[1000039],t,a,b,f[39][39];
double x[39],y[39],nowx,nowy,x1,x2,y1,y2;
int main(){
//	freopen("1.in","r",stdin);
	register int i,j,k;
	scanf("%d",&t);
	for(i=0;i<(1<<18);i++){
		for(j=1;j<=18;j++) if(!(i&(1<<j-1))){g[i]=j;break;}
	}
	while(t--){
		scanf("%d%d",&n,&m);memset(dp,0x3f,sizeof(dp));dp[0]=0;
		for(i=1;i<=n;i++) scanf("%lf%lf",&x[i],&y[i]),dp[(1<<i-1)]=1;
		for(i=1;i<=n;i++){
			for(j=1;j<=n;j++){
				f[i][j]=0;
				x1=x[i];x2=x[j];y1=y[i];y2=y[j];
				if(abs(x1-x2)<=eps) continue;
				nowx=(y1*x2-y2*x1)/(x1*x1*x2-x2*x2*x1);
				nowy=(y1-nowx*x1*x1)/x1;
				if(nowx>0) continue;
				for(k=1;k<=n;k++) 
				if(abs(nowx*x[k]*x[k]+nowy*x[k]-y[k])<=eps) f[i][j]|=1<<k-1;
			}
		}
		for(i=0;i<(1<<n)-1;i++){
			for(j=1;j<=n;j++) dp[i|f[g[i]][j]]=min(dp[i|f[g[i]][j]],dp[i]+1);
			for(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]);
	}
}
上一篇:JZOJ 4896. 【NOIP2016提高A组集训第16场11.15】兔子


下一篇:「NOIP2016」天天爱跑步