1. 程式人生 > >【題解】NOIP2016憤怒的小鳥

【題解】NOIP2016憤怒的小鳥

拋物線 post 作用 get spa tchar define bre ini

一眼n<=18狀壓dp……方程什麽的都很顯然,枚舉兩只小鳥,再將這條拋物線上的小鳥抓出來就好啦。只是這樣O(n^3)的dp必然是要TLE的,我一開始這樣交上去顯然跑得巨慢無比,後來轉念一想:面對一個嶄新的情況的時候,只有搭配的優劣之分,沒有先後的區別,所以最外面的一層可以直接去掉,變成O(n^2)的dp。這樣就跑的很快啦~

PS:print()函數只是調試輸出,作用是輸出now 的二進制形式+dp[now];

#include <bits/stdc++.h>
using namespace std;
#define db double
#define eps 0.00000001
#define
maxn 30 #define maxm (1 << 18) + 20 #define INF 999999 int T, n, m, dp[maxm], len; db a, b, x[maxn], y[maxn]; int read() { int x = 0, k = 1; char c; c = getchar(); while(c < 0 || c > 9) { if(c == -) k = -1; c = getchar(); } while(c >= 0 && c <= 9
) x = x * 10 + c - 0, c = getchar(); return x * k; } void Get_ab(db x1, db y1, db x2, db y2) { a = (y1 * x2 - y2 * x1) / (x1 * x1 * x2 - x2 * x2 * x1); b = (x2 * x2 * y1 - x1 * x1 * y2) / (x1 * x2 * x2 - x1 * x1 * x2); } bool On_Line(db x1, db y1) { db r = x1 * x1 * a + x1 * b; if
((r - y1 < eps) && (r - y1 > -eps)) return true; else return false; } void print(int now) { int a[30], tot = 0; int k = now; while(k) { a[++ tot] = k & 1; k >>= 1; } cout << now << " "; for(int i = 1; i <= tot; i ++) cout << a[i]; for(int i = n; i > tot; i --) cout <<0; cout << " " << dp[now]; cout << endl; } void DP(int now) { if(dp[now] != INF) return; for(int i = 0; i < n; i ++) { if(((1 << i) & now)) continue; for(int j = i + 1; j < n; j ++) { if(x[i] == x[j]) continue; Get_ab(x[i], y[i], x[j], y[j]); if(a >= 0) continue; int aft = 0; for(int k = 0; k < n; k ++) if(On_Line(x[k], y[k])) aft = (aft | (1 << k)); int tem = aft | now; DP(tem); dp[now] = min(dp[now], dp[tem] + 1); } int aft = (1 << i); int tem = aft | now; DP(tem); dp[now] = min(dp[now], dp[tem] + 1); break; } } void init() { len = (1 << n) - 1; for(int i = 0; i < len; i ++) dp[i] = INF; } int main() { T = read(); while(T --) { n = read(), m = read(); init(); for(int i = 0; i < n; i ++) scanf("%lf%lf", &x[i], &y[i]); dp[len] = 0; DP(0); printf("%d\n", dp[0]); } return 0; }

【題解】NOIP2016憤怒的小鳥