原題傳送門
俗話說得好,三點確定一條拋物線
起點是,所以兩隻豬可以確定出一條有用的拋物線
枚舉這兩隻豬,求出拋物線,求出這條拋物線可以經過哪些豬,把這個壓成二進制狀態進行狀壓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;
}