【題解】LuoGu2831:憤怒的小鳥

原題傳送門
俗話說得好,三點確定一條拋物線
起點是(0,0)(0,0),所以兩隻豬可以確定出一條有用的拋物線
枚舉這兩隻豬,求出拋物線,求出這條拋物線可以經過哪些豬,把這個壓成二進制狀態進行狀壓dp
注意一些細節,比如有些豬隻能自己一條拋物線

Code:

#include <bits/stdc++.h>
#define maxn 1000010
#define eps 1e-8
using namespace std;
int power[25], dp[maxn], num[20][20], n, m;
double x[25], y[25];

int check(double a, double b, int i){ return fabs(y[i] - a * x[i] * x[i] - b * x[i]) <= eps; }

int main(){
	int T;
	scanf("%d", &T);
	power[0] = 1;
	for (int i = 1; i <= 20; ++i) power[i] = power[i - 1] << 1;
	while (T--){
		memset(num, 0, sizeof(num));
		scanf("%d%d", &n, &m);
		for (int i = 1; i <= n; ++i) scanf("%lf%lf", &x[i], &y[i]);
		for (int i = 1; i <= n; ++i)
			for (int j = i + 1; j <= n; ++j){
				double a = (x[j] * y[i] - x[i] * y[j]) / (x[i] * x[i] * x[j] - x[j] * x[j] * x[i]),
					   b = (y[j] - a * x[j] * x[j]) / x[j];
				if (a < 0)
				for (int k = 1; k <= n; ++k) 
					if (check(a, b, k)) num[i][j] |= power[k - 1];
			}
		memset(dp, 0x3f, sizeof(dp));
		dp[0] = 0;
		for (int i = 0; i <= power[n] - 1; ++i)
			for (int j = 1; j <= n; ++j)
			if (!(i & power[j - 1])){
				dp[i | power[j - 1]] = min(dp[i | power[j - 1]], dp[i] + 1);
				for (int k = j + 1; k <= n; ++k)
					dp[i | num[j][k]] = min(dp[i | num[j][k]], dp[i] + 1);
			}
		printf("%d\n", dp[power[n] - 1]);
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章