Luogu_P2831

Luogu

算法

  • 搜索

思路

由于 \(n \le 18\),可以考虑搜索。

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

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

\[\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 > answer\)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;
}
posted @ 2025-07-09 12:13  Fallen_Leaf  阅读(9)  评论(0)    收藏  举报