题目链接

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;
}