P2831 [NOIP 2016 提高组] 愤怒的小鸟
算法
- 搜索
思路
由于 ,可以考虑搜索。
定义 表示搜索到了第 头猪,使用了 条抛物线,前面还有 头猪为被击中。
对于一条抛物线 ,需要三个点确定其解析式。由于题目钦定了抛物线必定经过 ,所以还需要两个点。在前面为被击中的 头猪中选择一头与第 头猪配对。假设两头猪的坐标为 。则
于是就可以得到这两头猪配对的抛物线解析式。
然后进行剪枝。如果由于前面未配对的猪必须要有一条单独的抛物线经过,所以有最优性剪枝: 时 return。
代码
#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;}
Comments
Quiet notes for this article.