题目链接
https://codeforces.com/contest/698/problem/D
题解
玄妙好题啊
对于每个元素\(j\)判断\(j\)是否可被射中。假设我们要用第\(i\)个弓箭射中第\(j\)个目标,那么在射中之前有若干个目标是我们需要先射中的。但我们并不知道应该用哪些目标射中。
于是我们可以枚举一个\(1\)至\(m\)的全排列\(P_k\), 然后进行BFS. 初始队列中只有\(j\),每次取出队首元素(设队首在队列中的位置为\(k\)),然后用\(P_k\)去射队首元素,然后加入队列。若队列中元素个数超过\(m\), 则无解(以这个顺序射中\(j\)是不可能的)。
时间复杂度\(O(k!kn)\)
代码
#include<bits/stdc++.h>
#define llong long long
#define mkpr make_pair
#define riterator reverse_iterator
using namespace std;
inline int read()
{
int x = 0,f = 1; char ch = getchar();
for(;!isdigit(ch);ch=getchar()) {if(ch=='-') f = -1;}
for(; isdigit(ch);ch=getchar()) {x = x*10+ch-48;}
return x*f;
}
const int N = 1000;
const int M = 7;
struct Point
{
int x,y;
} a[M+2],b[N+3];
vector<int> l[M+2][N+3];
int permu[M+2];
int que[N+3]; bool vis[N+3];
int n,m;
int main()
{
scanf("%d%d",&m,&n);
for(int i=1; i<=m; i++) scanf("%d%d",&a[i].x,&a[i].y);
for(int i=1; i<=n; i++) scanf("%d%d",&b[i].x,&b[i].y);
for(int i=1; i<=m; i++)
{
for(int j=1; j<=n; j++)
{
for(int k=1; k<=n; k++) if(k!=j)
{
if(1ll*(b[j].x-a[i].x)*(b[k].y-a[i].y)==1ll*(b[j].y-a[i].y)*(b[k].x-a[i].x) && (1ll*(a[i].x-b[k].x)*(b[j].x-b[k].x)<0 || (a[i].x==b[k].x&&1ll*(a[i].y-b[k].y)*(b[j].y-b[k].y)<0)))
{
l[i][j].push_back(k);
}
}
}
}
int fans = 0;
for(int j=1; j<=n; j++)
{
for(int i=1; i<=m; i++) permu[i] = i;
bool ans = false;
do
{
for(int i=1; i<=n; i++) vis[i] = false;
bool cur = true;
int hd = 1,tl = 1; que[tl] = j; vis[j] = true;
while(hd<=tl)
{
int u = que[hd];
for(int i=0; i<l[permu[hd]][u].size(); i++)
{
if(vis[l[permu[hd]][u][i]]) continue;
que[++tl] = l[permu[hd]][u][i]; vis[l[permu[hd]][u][i]] = true;
if(tl>m) {cur = false; break;}
}
if(!cur) {break;}
hd++;
}
if(cur) {ans = true; break;}
} while(next_permutation(permu+1,permu+m+1));
if(ans) {fans++;}
}
printf("%d\n",fans);
return 0;
}