题目大意:
k k k个射击点,平面上有 n n n只怪兽,每个射击点只能射击一次,且只能射击方向上第一个没死的怪兽。射击顺序任意,有多少只怪物可能被打死。
解题思路:
- 整了个特别不好实现的思路…最后看的题解
- 枚举每只怪兽 x x x,对于每只怪兽, k ! k! k!枚举开枪顺序,模拟过程大概是:第一枪 p 1 p_1 p1要射中 x x x,倘若中间有怪兽 y y y,那么第二枪 p 2 p_2 p2就要去射击 y y y,如果 p 2 p_2 p2与 y y y之间有怪兽 z z z在中间,则继续递归下去即可
- 预处理设计点和每个怪兽中间的怪兽,时间复杂度为 O ( k n 2 ) O(kn^2) O(kn2)
- 枚举怪兽能否被杀的时间复杂度为: O ( k ! n k ) O(k!nk) O(k!nk)
- 总时间复杂度: O ( k n 2 + k ! n k ) O(kn^2+k!nk) O(kn2+k!nk)
AC代码:
#include <bits/stdc++.h>
#define ft first
#define sd second
#define pb push_back
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) //不能跟puts混用
#define seteps(N) fixed << setprecision(N)
#define endl "\n"
const int maxn = 1e3 + 10;
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;
const ll mod = 1e9 + 7;
int sgn(ll x) {
if (x == 0) return 0;
else return x < 0 ? -1 : 1;
}
struct Point {
ll x, y;
int id;
Point operator - (Point p) {return {x - p.x, y - p.y};}
Point operator + (Point p) {return {x + p.x, y + p.y};}
ll operator ^ (Point p) {return x * p.y - y * p.x;}
ll operator * (Point p) {return x * p.x + y * p.y;}
ll len2() {return x * x + y * y;}
ll dis2(Point p) {return (x - p.x) * (x - p.x) + (y - p.y) * (y - p.y);}
bool operator < (Point p) {return len2() < p.len2();}
bool operator == (Point p) {
if (x != p.x || y != p.y) return false;
else return true;
}
} sto[10], mon[maxn];
vector <int> id[10][maxn];
int k, n, rk[10];
bool pd(Point p1, Point p2, Point p3) {
int s = sgn((p3 - p1) ^ (p2 - p1));
if (s) return false; //在同一条直线
s = sgn((p3 - p1) * (p2 - p1));
if (s < 0) return false; //不是同一个方向
s = sgn(p1.dis2(p2) - p1.dis2(p3));
if (s <= 0) return false; //距离不大于
return true;
}
void init() {
for (int i = 1; i <= k; i++)
for (int j = 1; j <= n; j++)
for (int l = 1; l <= n; l++)
if (pd(sto[i], mon[j], mon[l])) {
id[i][j].pb(l);
if (id[i][j].size() == k) break;
}
}
queue <int> pq;
bool vis[maxn];
int num;
bool dfs(int x) {
if (num > k) return 0;
int s = rk[num];
for (int y : id[s][x]) {
if (!vis[y]) {
++num;
if (!dfs(y)) return 0;
}
}
return pq.push(x), vis[x] = 1;
}
void solve() {
int ans = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= k; j++) rk[j] = j;
do {
while (!pq.empty()) vis[pq.front()] = 0, pq.pop();
num = 1;
if (dfs(i)) {
++ans;
break;
}
} while (next_permutation(rk + 1, rk + k + 1));
}
cout << ans << endl;
}
int main() {
cin >> k >> n;
for (int i = 1; i <= k; i++) cin >> sto[i].x >> sto[i].y;
for (int i = 1; i <= n; i++) cin >> mon[i].x >> mon[i].y;
init();
solve();
return 0;
}