zoukankan      html  css  js  c++  java
  • 【noip2016d2t3】状压DP+巧妙优化

    题意可以简单这样考虑

    给出n^2个集合(每个集合的元素不超过n),包含某个元素的集合至少有n个,选出最少的集合,使这些集合的并包含n个元素

    n最大只有18

    可以考虑状压n个元素,然后枚举n^2个集合

    这样的复杂度是2^n*n^2

    但是我们可以这样考虑,因为最终的集合一定包含所有的元素,所以不妨预处理出每个状态中最靠左的0的位置,

    然后每次只需要考虑包含这个元素的n个集合(因为你最终一定要包含这个元素,所以不如就先包含它)

    这样复杂度就降低成2^n*n

    注意精度,以及两个点不一定能构成抛物线

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <vector>
    using namespace std;
    
    struct Pair
    {
        double x, y;
        Pair() {}
        Pair(double _x, double _y):x(_x), y(_y) {}
    }p[20];
    int Map[400][20];
    vector<int> State;
    int f[(1<<(20))], Hash[(1<<(20))];
    Pair Get(Pair A, Pair B)
    {
        if(A.x == B.x && A.y == B.y) B.x = A.x+1;
        double y = (B.y*A.x - B.x*A.y)/(B.x*B.x*A.x - A.x*A.x*B.x);
        double x = (A.y - y*A.x*A.x)/A.x;
        return Pair(x, y);
    }
    const double eps = 1e-3;
    bool On(Pair A, Pair X)
    {
        return abs(X.y - A.x*X.x - A.y*X.x*X.x) < eps;
    }
    int n, m, T;
    int And(int X, int i)
    {
        for(int j = 1; j <= n; j++)
            if(Map[i][j]) X = X|(1<<(j-1));
        return X;
    }
    void debug(int X)
    {
        for(int i = 0; i < n; i++) if(X&(1<<i)) cout<<1; else cout<<0;
        cout<<endl;
    }
    int main()
    {
        for(int i = 0; i <= (1<<20)-1; i++)
        {
            for(int j = 0; j <= 20; j++)
                if((i&(1<<j)) == 0) { Hash[i] = j+1; break; }
        }
        cin>>T;
        while(T--)
        {
            cin>>n>>m;
            memset(Map, 0, sizeof(Map));
            memset(f, 0, sizeof(f));
            State.clear(); State.push_back(0);
            for(int i = 1; i <= n; i++) cin>>p[i].x>>p[i].y;
            int tot = 1;
            for(int i = 1; i <= n; i++)
                for(int j = 1; j <= n; j++)
                {
                    Pair temp = Get(p[i], p[j]);
                    if(temp.y >= 0) continue;
                    for(int k = 1; k <= n; k++)
                        if(On(temp, p[k]))
                            Map[(i-1)*n+j][k] = 1;
                }
            int k = 0, M = (1<<n)-1;
            while(f[M] == 0)
            {
                int sz = State.size();
                for(int s = k; s < sz; s++)
                {
                    for(int i = 1; i <= n; i++)
                    {
                        int s2 = And(State[s], (Hash[State[s]]-1)*n+i);                  
                        if(f[s2] == 0 && s2 != 0)
                        {
                            f[s2] = f[State[s]] + 1;
                            State.push_back(s2);
                        }else
                            f[s2] = min(f[s2], f[State[s]] + 1);
                    }
                }
                k = sz;          
            }
            cout<<f[(1<<n)-1]<<endl;
        }
    }
  • 相关阅读:
    获取Enum枚举值描述的几法方法
    Android开发入门 Button事件实现的方法(原创)
    最有价值的.Net第三方控件
    Eclipse快捷键大全(转载)
    recovery教程
    XP系统通过无线网卡共享宽带给其他设备,正确的共享设置(修正版,绝对可行)
    使用Eclipse写QT
    Android 4.0模拟器弹出“谷歌拼音输入法”已停止运行的解决方法
    C# 枚举用法总结
    谷歌安卓系统使用必读,什么是root, Recovery, Radio, APP TO SD, Rom
  • 原文地址:https://www.cnblogs.com/Saurus/p/6086543.html
Copyright © 2011-2022 走看看