Codeforces 698D Limak and Shooting Points (搜索)

题目链接

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

猜你喜欢

转载自www.cnblogs.com/suncongbo/p/12348088.html