zoukankan      html  css  js  c++  java
  • 【NOIP2016提高组】愤怒的小鸟

    https://www.luogu.org/problem/show?pid=2831

    BFS

    看到N这么小就可以想到搜索,求最少步数显然应该用BFS

    在这题中过两猪可以唯一确定一条抛物线,每一步可以发射两只猪确定的一条抛物线(打下这条抛物线上的所有猪),也可以发射一条只经过一只猪的抛物线(只打下这只猪)。

    这时可以想到状压存储每个状态,并且读入所有猪时预处理一下每两只猪确定的抛物线。

    两点确定一条过原点的抛物线y=ax2+bx的方法:点(x1, y1) (x2, y2)过抛物线,得y1=ax12+bx1,y2=ax22+bx2,两式分别变形得y1/x1-ax1=y2/x2-ax2=b,再整理得a=(y2/x2-y1/x1)/(x2-x1)。求出a后往回代可求出b。

    记得记录每个状态是否已经搜索过,避免重复的状态入队。由于共有2n个状态,故时间复杂度是O(2n)的。如果不剪枝就是O(n!)。

    题目给的m应该是用来xjb剪枝用的,但是m=2怎么用我也不懂……

    注意事项:

    • 判断两个浮点数相等要考虑精度误差。
    • stl的queue不开优化会很慢,可以考虑手写队列。
    #include <algorithm>
    #include <cstring>
    #include <iostream>
    #include <queue>
    #include <vector>
    #include <cmath>
    using namespace std;
    bool equal(double x, double y, double eps = 1e-6)
    {
        return fabs(x - y) <= eps;
    }
    int n;
    bool m[3];
    pair<double, double> pigs[20];
    unsigned target;       // 搜索的最终目标,即第1~n位均为1
    unsigned pwxs[20][20]; // pwxs[i][j] => i、j两只猪所在抛物线上的所有猪
    bool visited[(1 << 20)];
    int bfs()
    {
        typedef pair<unsigned, int> state; // <状态, 步数>
        queue<state> q;
        q.push(make_pair(0, 0));
        while (!q.empty())
        {
            state x = q.front();
            q.pop();
    
            // 用一只鸟打一只猪的情况
            for (int i = 1; i <= n; i++)
            {
                if (!(x.first & (1 << i))) // 如果i猪还没被打下
                {
                    state y = x;
                    y.first |= (1 << i);
                    y.second++;
                    if (y.first == target)
                        return y.second;
                    if (!visited[y.first] && !(m[1] && y.second > (int)(n * 1.0 / 3 + 1)))
                    {
                        q.push(y);
                        visited[y.first] = true;
                    }
                }
            }
    
            // 用一只鸟打两只猪的情况
            for (int i = 1; i <= n; i++)
            {
                for (int j = i + 1; j <= n; j++)
                {
                    if (!(x.first & (1 << i)) && !(x.first & (1 << j)))  // 如果i、j猪都还没被打下
                    {
                        state y = x;
                        y.first |= pwxs[i][j];
                        y.second++;
                        if (y.first == target)
                            return y.second;
                        if (!visited[y.first] && !(m[1] && y.second > (int)(n * 1.0 / 3 + 1)))
                        {
                            q.push(y);
                            visited[y.first] = true;
                        }
                    }
                }
            }
        }
        return -1;
    }
    int main()
    {
        ios::sync_with_stdio(false);
        int t;
        cin >> t;
        while (t--)
        {
            memset(visited, false, 1 << 20);
    
            int c;
            cin >> n >> c;
            m[c] = true;
    
            for (int i = 1; i <= n; i++)
                for (int j = 1; j <= n; j++)
                    pwxs[i][j] = 0;
    
            target = 0;
            for (int i = 1; i <= n; i++)
                target |= (1 << i);
    
            double a, b;
            for (int i = 1; i <= n; i++)
            {
                cin >> a >> b;
                pigs[i] = make_pair(a, b);
            }
    
            for (int i = 1; i <= n; i++)
            {
                for (int j = i + 1; j <= n; j++)
                {
                    /* ∵ y1=ax1^2+bx1, y2=ax2^2+bx2
                       ∴ b=y1/x1-ax1=y2/x2-ax2
                       ∴ a=(y2/x2-y1/x1)/(x2-x1) */
                    double &x1 = pigs[i].first, &y1 = pigs[i].second;
                    double &x2 = pigs[j].first, &y2 = pigs[j].second;
                    a = (y2 / x2 - y1 / x1) / (x2 - x1);
                    b = y1 / x1 - a * x1;
                    if (a < 0)
                    {
                        for (int k = 1; k <= n; k++)
                        {
                            double &x = pigs[k].first, &y = pigs[k].second;
                            if (equal(a * x * x + b * x, y))
                                pwxs[i][j] |= (1 << k);
                        }
                    }
                }
            }
            cout << bfs() << endl;
        }
        return 0;
    }

    看到N这么小就可以想到搜索,求最少步数显然应该用BFS

    在这题中过两猪可以唯一确定一条抛物线,每一步可以发射两只猪确定的一条抛物线(打下这条抛物线上的所有猪),也可以发射一条只经过一只猪的抛物线(只打下这只猪)。

    这时可以想到状压存储每个状态,并且读入所有猪时预处理一下每两只猪确定的抛物线。

    记得记录每个状态是否已经搜索过,避免重复的状态入队。

  • 相关阅读:
    使用VisualStudio进行单元测试之二
    使用VisualStudio进行单元测试之一
    ExtJS监听键盘事件:回车键实现登录功能
    PPTP无法连网
    Android深度探索.
    Android深度探索
    Android驱动开发
    window.open()的具体使用方法
    js控制的几种页面跳转和传值(转载)
    Hatching shader
  • 原文地址:https://www.cnblogs.com/ssttkkl/p/7124206.html
Copyright © 2011-2022 走看看