zoukankan      html  css  js  c++  java
  • CodeForces 698D Limak and Shooting Points

    CodeForces 698D Limak and Shooting Points

    https://codeforces.com/contest/698/problem/D

    (n) 个怪兽和 (k) 个魔法石.第 (i) 只怪兽位于 ((mx_i, my_i))

    每个魔法石最多只能使用一次,可以按任意顺序使用魔法石,使用第 (i) 个魔法石可以传送至 ((ax_i, ay_i)) ,然后向任意方向射出一只箭,然后箭会消灭掉这个方向上第一只怪兽,然后消失.

    问有多少只怪兽可能被消灭掉.

    (1 le k le 7, 1 le n le 1000)

    (-10^9 le ax_i,ay_i le 10^9)

    (-10^9 le mx_i,my_i le 10^9)

    给出的 (n + k) 个点坐标两两不同.

    Tutorial

    https://sunnuozhou.github.io/2020/01/16/codeforces-698D/

    由于 (k) 很小, 考虑搜索.

    首先,预处理出第 (i) 个魔法石位置和第 (j) 只怪兽之间的所有怪兽.

    考虑依次判断第 (x) 只怪兽是否可以被消灭. 可以首先将 (x) 加入队列,然后进行以下循环

    • 若队列为空,则可以被消灭
    • 否则,取出队首元素,设为 (u)
    • 分配一个未使用的魔法石 (v) ,表示是使用 (v) 消灭了 (u) .
    • (v, u) 之间的怪兽加入队列

    注意若某一时刻进入过队列的元素超过 (k) , 则无解.

    预处理的复杂度为 (O(n^2k)) ,判断部分复杂度为 (O(nk cdot k!))

    Code

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <vector>
    #define debug(...) fprintf(stderr, __VA_ARGS__)
    using namespace std;
    typedef long long ll;
    const int maxk = 10;
    const int maxn = 1000 + 5;
    int k, n;
    int ax[maxk], ay[maxk];
    int mx[maxn], my[maxn];
    bool flag; 
    bool inq[maxn];
    bool vis[maxk];
    vector<int> pos;
    vector<int> r[maxk][maxn];
    inline ll det(int x0, int y0, int x1, int y1) { return (ll)x0 * y1 - (ll)y0 * x1; }
    inline ll dot(int x0, int y0, int x1, int y1) { return (ll)x0 * x1 + (ll)y0 * y1; }
    inline ll norm(int x, int y) { return dot(x, y, x, y); }
    inline bool check(int x0, int y0, int x1, int y1)
    {
        if (det(x0, y0, x1, y1))
            return 0;
        if (dot(x0, y0, x1, y1) < 0)
            return 0;
        if (norm(x0, y0) < norm(x1, y1))
            return 0;
        return 1;
    }
    void dfs(int step)
    {
        if (step == pos.size())
            flag = 1;
        if (flag)
            return;
        int u = pos[step], rec = pos.size();
        for (int i = 1; i <= k; ++i) if (!vis[i])
        {
            vis[i] = 1;
            for (int j = 0; j < r[i][u].size(); ++j)
            {
                int x = r[i][u][j];
                if (!inq[x])
                {
                    inq[x] = 1;
                    pos.push_back(x);
                    if (pos.size() > k)
                        break;
                }
            }
            if (pos.size() <= k)
            {
                dfs(step + 1);
                if (flag) return;
            }
            while (pos.size() > rec)
            {
                int x = pos.back(); pos.pop_back();
                inq[x] = 0;
            }
            vis[i] = 0;
        }
    }
    int sol()
    {
        for (int i = 1; i <= k; ++i)
            for (int j = 1; j <= n; ++j)
                for (int k = 1; k <= n; ++k) if(j != k)
                    if (check(mx[j] - ax[i], my[j] - ay[i], mx[k] - ax[i], my[k] - ay[i]))
                        r[i][j].push_back(k);
        int an = 0;
        for (int i = 1; i <= n; ++i)
        {
            flag = 0;
            pos.clear(), pos.push_back(i);
            memset(vis, 0, sizeof(vis));
            memset(inq, 0, sizeof(inq));
            dfs(0);
            if (flag) ++an;
        }
        return an;
    }
    int main()
    {
        scanf("%d%d", &k, &n);
        for (int i = 1; i <= k; ++i)
            scanf("%d%d", &ax[i], &ay[i]);
        for (int i = 1; i <= n; ++i)
            scanf("%d%d", &mx[i], &my[i]);
        printf("%d
    ", sol());
        return 0;
    }
    
  • 相关阅读:
    php 解析json
    TP学习笔记一(tp的目录结构 , tp的输出方式)
    linux android真机测试
    SharedPreferences保存数据
    Volley用法
    android获得图片
    android 一条线
    android 获取时间
    Android_Spinner_Listener
    Android_Spinner_SimpleAdapter
  • 原文地址:https://www.cnblogs.com/ljzalc1022/p/12873002.html
Copyright © 2011-2022 走看看