1. 程式人生 > >[luoguP2831] 憤怒的小鳥(狀壓DP)

[luoguP2831] 憤怒的小鳥(狀壓DP)

狀壓 集合 blank tin 處理 cstring tps www. cpp

傳送門

感覺這題不是很難,但是很惡心。

說一下幾點。

1.預處理出來每兩個點所構成的拋物線能消除的豬的集合。

2.如果兩個點橫坐標相同,則不能構成拋物線

3.a >= 0 continue

4.卡精度

5.卡常數(本蒟蒻巨菜,2nn2做法)

#include <cstdio>
#include <cstring>
#define N 19
#define abs(x) ((x) < 0 ? -(x) : (x))
#define min(x, y) ((x) < (y) ? (x) : (y))

int T, n, m, S;
int f[1 << N], s[N][N];
double X[N], Y[N], a, b;

inline bool pd(double x, double y)
{
	return abs(x - y) < (1e-6);
}

int main()
{
	int i, j, k, l;
	scanf("%d", &T);
	while(T--)
	{
		scanf("%d %d", &n, &m);
		memset(f, 127 / 3, sizeof(f));
		for(i = 1; i <= n; i++) scanf("%lf %lf", &X[i], &Y[i]);
		memset(s, 0, sizeof(s));
		for(i = 1; i <= n; i++)
			for(j = i + 1; j <= n; j++)
			{
				if(pd(X[i], X[j])) continue;
				a = (Y[j] / X[j] - Y[i] / X[i]) / (X[j] - X[i]);
                b = Y[i] / X[i] - a * X[i];
				if(a >= 0) continue;	
				s[i][j] |= (1 << i - 1) | (1 << j - 1);
				for(k = 1; k <= n; k++)
					if(k != i && k != j && pd(Y[k], a * X[k] * X[k] + b * X[k]))
						s[i][j] |= 1 << k - 1;
			}
		f[0] = 0;
		for(i = 0; i < (1 << n); i++)
			for(j = 1; j <= n; j++)
				if(!(i & (1 << j - 1)))
				{
					f[i | (1 << j - 1)] = min(f[i | (1 << j - 1)], f[i] + 1);
					for(k = j + 1; k <= n; k++)
						if((i & (1 << k - 1)) && s[j][k])
						{
							S = i ^ (i & s[j][k]);
							f[i | (1 << j - 1)] = min(f[i | (1 << j - 1)], f[S] + 1);
						}
				}
		printf("%d\n", f[(1 << n) - 1]);
	}
	return 0;
}

  

[luoguP2831] 憤怒的小鳥(狀壓DP)