1. 程式人生 > 其它 >洛谷P2831 [NOIP2016 提高組] 憤怒的小鳥——狀壓dp、預處理

洛谷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;
}

浮生若夢,為歡幾何