1. 程式人生 > >【題解】洛谷P2831[NOIP2016]憤怒的小鳥 狀壓DP

【題解】洛谷P2831[NOIP2016]憤怒的小鳥 狀壓DP

題目連結
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述

dp[i]表示i狀態時所需要的最少的小鳥數,state[i]表示第i條拋物線所打掉的小豬狀態,
dp[i|state[j]]=min(dp[i|state[j]],dp[i]+1)

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define eps 1e-6
int n,m;
const int N=18;
int dp[1<<N];//dp[i]表示i狀態時所需最少小鳥數 
double x[N],y[N];
int state[510];//記錄每條拋物線 
int cnt; 
int main()
{
	//freopen("in.txt","r",stdin);
	int t;
	double a,b;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&m);
		cnt=0;
		memset(dp,0x3f,sizeof(dp));
		dp[0]=0;
		for(int i=0;i<n;i++)
		scanf("%lf%lf",&x[i],&y[i]);
		for(int i=0;i<n;i++)
		{
			state[cnt++]=(1<<i);
			for(int j=i+1,k=0;j<n;j++)
			{
				if((k>>j)&1)continue;
				a=(y[j]*x[i]-y[i]*x[j])/(x[i]*x[j]*(x[j]-x[i]));
				b=(y[i]*x[j]*x[j]-y[j]*x[i]*x[i])/(x[i]*x[j]*(x[j]-x[i]));
				if(a>=-eps)continue;
				state[cnt]=(1<<i);
				for(int o=j;o<n;o++)
				if(fabs(a*x[o]*x[o]+b*x[o]-y[o])<=eps)
				{
					k|=(1<<o);
					state[cnt]|=(1<<o);
				}
				cnt++;
			}
		}
		for(int i=0;i<(1<<n);i++)
		for(int j=0;j<cnt;j++)
		dp[i|state[j]]=min(dp[i|state[j]],dp[i]+1);
		printf("%d\n",dp[(1<<n)-1]);
	}
	return 0;
}