原题传送门
俗话说得好,三点确定一条抛物线
起点是,所以两只猪可以确定出一条有用的抛物线
枚举这两只猪,求出抛物线,求出这条抛物线可以经过哪些猪,把这个压成二进制状态进行状压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;
}