Luogu

算法

  • 搜索

思路

由于 n18n \le 18,可以考虑搜索。

定义 dfs(cur,a,b)dfs(cur, a, b) 表示搜索到了第 curcur 头猪,使用了 aa 条抛物线,前面还有 bb 头猪为被击中。

对于一条抛物线 y=ax2+bx+cy=ax^{2}+bx+c,需要三个点确定其解析式。由于题目钦定了抛物线必定经过 (0,0)(0,0),所以还需要两个点。在前面为被击中的 bb 头猪中选择一头与第 curcur 头猪配对。假设两头猪的坐标为 (x1,y1),(x2,y2)(x_{1}, y_{1}), (x_{2},y_{2})。则

{ax12+bx1=y1ax22+bx2=y2{a=(y1x2y2x1)x12x2x1x22b=y1x12ax1\begin{cases} a x_{1}^{2} + b x_{1} = y_{1} \\ a x_{2}^{2} + b x_{2} = y_{2} \\ \end{cases} \to \begin{cases} a = \frac{(y_{1} x_{2} - y_{2} x_{1})}{x_{1}^{2} x_{2} - x_{1} x_{2}^{2}} \\ b = \frac{y_{1} - x_{1}^{2} a}{x_{1}} \\ \end{cases}

于是就可以得到这两头猪配对的抛物线解析式。

然后进行剪枝。如果由于前面未配对的猪必须要有一条单独的抛物线经过,所以有最优性剪枝: a+b>answera + b > answerreturn

代码

#include <bits/stdc++.h>

using namespace std;

constexpr int N = 25;
constexpr double EPS = 1e-9;
pair<double, double> pig[N], line[N], unused[N];
int test_case, n, m, answer;

bool equal(double a, double b) {
return fabs(a - b) < EPS;
}

void dfs(int cur, int a, int b) {
if (a + b >= answer) {
return void();
} else if (cur > n) {
answer = min(answer, a + b);
return void();
}

double x = pig[cur].first, y = pig[cur].second;

bool crossed = false;
for (int i = 1; i <= a; i++) {
if (equal(line[i].first * x * x + line[i].second * x, y) == true) {
crossed = true;
break;
}
}

if (crossed == true) {
dfs(cur + 1, a, b);
} else {
for (int i = 1; i <= b; i++) {
double tx = unused[i].first, ty = unused[i].second;

if (equal(x, tx) == true) {
continue;
}

double pa = (y * tx - ty * x) / (x * x * tx - tx * tx * x);
double pb = (y - x * x * pa) / x;

if (pa >= 0) {
continue;
}

line[a + 1] = make_pair(pa, pb);

pair<double, double> tmp = unused[i];
for (int j = i; j <= b - 1; j++) {
unused[j] = unused[j + 1];
}

dfs(cur + 1, a + 1, b - 1);

for (int j = b; j > i; j--) {
unused[j] = unused[j - 1];
}

unused[i] = tmp;
}

unused[b + 1] = pig[cur];
dfs(cur + 1, a, b + 1);
}
}

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);

cin >> test_case;

while (test_case --) {
cin >> n >> m;

for (int i = 1; i <= n; i++) {
cin >> pig[i].first >> pig[i].second;
}

answer = 100000;
dfs(1, 0, 0);

cout << answer << "\n";
}

return 0;
}