洛谷P2831 [NOIP2016 提高组] 愤怒的小鸟——状压dp、预处理

题目链接

题目:愤怒的小鸟

思路过程

数据范围非常小,\(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;
}

上一篇:CSS3中background属性的调整


下一篇:python基础之---else(十)