zoukankan      html  css  js  c++  java
  • Luogu 2831 [NOIP2016] 愤怒的小鸟

    第一眼看成爆搜的状压dp,膜Chester大神犇。

    考虑到三个不在同一直线上的点可以确定一条抛物线,而固定点$(0, 0)$和不在同一直线上这两个条件是题目中给定的,所以我们只要枚举两个点然后暴力算抛物线,然后chk一遍观察一下多少点在这一条抛物线上就行了。

    想到状压之后状态和方程就显然了。

    注意判解出来的抛物线$a leqslant 0$的情况, eps开小一点。

    因为决策集合的大小是$O(n ^ {2})$级别的,所以时间复杂度为$O(Tn^{2}2^{n})$。

    Code:

    #include <cstdio>
    #include <cstring>
    using namespace std;
    typedef double db;
    
    const int N = 20;
    const int S = (1 << 18) + 5;
    const int inf = 0x3f3f3f3f;
    const db eps = 1e-6;
    
    int testCase, n, m, q[N * (N + 1)], f[S];
    bool vis[S];
    
    struct Node {
        db x, y;
    } a[N];
    
    inline db fabs(db x) {
        return x > 0 ? x : -x;
    }
    
    inline bool chk0(db x) {
        return fabs(x) < eps;
    }
    
    inline void chkMin(int &x, int y) {
        if(y < x) x = y;
    }
    
    inline int calc(int u, int v) {
        db a1 = a[u].x * a[u].x, b1 = a[u].x, c1 = a[u].y;
        db a2 = a[v].x * a[v].x, b2 = a[v].x, c2 = a[v].y;
        if(chk0((b1 * a2 - b2 * a1)) || chk0((a1 * b2 - b1 * a2))) return 0;
        db y = (c1 * a2 - c2 * a1) / (b1 * a2 - b2 * a1);
        db x = (c1 * b2 - c2 * b1) / (a1 * b2 - b1 * a2);
        if(x > 0 ||chk0(x)) return 0;
        int res = (1 << (u - 1)) | (1 << (v - 1));
        for(int i = 1; i <= n; i++) {
            if(i == u || i == v) continue;
            if(chk0(x * a[i].x * a[i].x + y * a[i].x - a[i].y)) res |= (1 << (i - 1));
        }
        return res;
    }
    
    int main() {
        for(scanf("%d", &testCase); testCase--; ) {
            scanf("%d%d", &n, &m);
            for(int i = 1; i <= n; i++) scanf("%lf%lf", &a[i].x, &a[i].y);
            
            m = 0;
            memset(vis, 0, sizeof(vis));
            for(int i = 1; i <= n; i++) 
                for(int j = 1; j < i; j++) {
                    int s = calc(i, j);
                    if(vis[s] || s == 0) continue;
                    vis[s] = 1;
                    q[++m] = s;    
                }
            for(int i = 1; i <= n; i++) q[++m] = (1 << (i - 1));
            
    /*        for(int i = 1; i <= m; i++)
                printf("%d ", q[i]);
            printf("
    ");   */
                
            memset(f, 0x3f, sizeof(f));
            f[0] = 0;
            for(int s = 0; s < (1 << n); s++) 
                for(int i = 1; i <= m; i++)
                    chkMin(f[s | q[i]], f[s] + 1);
            
            printf("%d
    ", f[(1 << n) - 1]);
        }
        return 0;
    }  
    View Code
  • 相关阅读:
    HDU1266 Reverse Number
    codevs1380 没有上司的舞会
    codevs1163 访问艺术馆
    codevs2144 砝码称重 2
    codevs1553 互斥的数
    codevs1230 元素查找
    codevs3118 高精度练习之除法
    codevs1245 最小的N个和
    codevs1063 合并果子
    codevs1052 地鼠游戏
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/9532875.html
Copyright © 2011-2022 走看看