zoukankan      html  css  js  c++  java
  • [POJ1038]状压DP

    题意:给一个n*m的区域,里面有一些障碍物,往里面放2*3和3*2的矩形,矩形之间不能重叠,不能覆盖到障碍物,求能放置的最大个数。(n<=150,m<=10)

    思路:看到m=10就应该往状压dp方面想了。由于有3*2的矩形,所以需要记录2行的状态,粗略估计状态数高达150*2^20=1.5*1e8,这么多状态必然超时,注意到如果(i-1,j)为0了,无论(i,j)为1或0,(i,j)都不能放矩形,于是知道有很多无用的或者说不合法的状态,两行的状态用m位3进制数表示同样能实现转移。由于3进制数操作起来麻烦,不妨用4进制代替3进制,从当前状态向后递推,新状态存在vector里,使用的时候先排序,然后跳过重复或不够优的状态来向后扩展。经测试,极限数据下,vector里有40000多个状态,有效状态只有1700多个,一下子降了一个数量级,简直逆天...对于这种存在大量无效状态的dp ,用vector+向后递推+排序去重有奇效。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <cstdlib>
    #include <cstring>
    #include <vector>
    #include <ctime>
    #include <deque>
    #include <queue>
    #include <algorithm>
    using namespace std;
     
    void readInt(){}void RI(int&X){scanf("%d",&X);}template<typename...R>
    void RI(int&f,R&...r){RI(f);RI(r...);}void RIA(int*p,int*q){int d=p<q?1:-1;
    while(p!=q){scanf("%d",p);p+=d;}}void print(){cout<<endl;}template<typename T>
    void print(const T t){cout<<t<<endl;}template<typename F,typename...R>
    void print(const F f,const R...r){cout<<f<<", ";print(r...);}template<typename T>
    void print(T*p, T*q){int d=p<q?1:-1;while(p!=q){cout<<*p<<", ";p+=d;}cout<<endl;}
     
    template<typename T>bool umax(T &a, const T &b) {
        return a >= b? false : (a = b, true);
    }
     
    typedef pair<intint> pii;
     
    #define pb push_back
    #define mp make_pair
    #define X first
    #define Y second
    #define all(a) (a).begin(), (a).end()
     
    vector<pii> dp[2];
    bool cmp(const pii &a, const pii &b) {
        return a.X < b.X || a.X == b.X && a.Y > b.Y;
    }
    int sta[157], now, row, ttl, n, m, k;
    pii s;
     
    bool chk(const int &s, const int &p) {
        return s & (1 << p);
    }
     
    void dfs(int col, int S, int V) {
        if (col == m) {
            dp[now ^ 1].pb(mp(S, V));
            return ;
        }
        dfs(col + 1, S, V);
        int low = S & ttl, high = S >> m, r = low | high;
        if (col + 2 < m && !chk(r, col) && !chk(r, col + 1) && !chk(r, col + 2)) {
            int h = (1 << col) ^ (1 << (col + 1)) ^ (1 << (col + 2));
            dfs(col + 3, (high ^ h) << m | (low ^ h), V + 1);
        }
        r |= s.X >> m;
        if (col + 1 < m && !chk(r, col) && !chk(r, col + 1)) {
            int h = (1 << col) ^ (1 << (col + 1));
            dfs(col + 2, (high ^ h) << m | (low ^ h), V + 1);
        }
    }
     
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("in.txt""r", stdin);
    #endif // ONLINE_JUDGE
        int T;
        cin >> T;
        while (T --) {
            RI(n, m, k);
            memset(sta, 0, sizeof(sta));
            for (int i = 0; i < k; i ++) {
                int x, y;
                RI(x, y);
                sta[x] ^= 1 << (y - 1);
            }
            dp[0].clear();
            dp[1].clear();
            now = 0;
            ttl = (1 << m) - 1;
            dp[0].pb(mp(ttl << m | sta[1], 0));
            for (int i = 1; i < n; i ++) {
                dp[now ^ 1].clear();
                sort(all(dp[now]), cmp);
                int sz = dp[now].size();
                for (int j = 0; j < sz; j ++) {
                    s = dp[now][j];
                    if (!j || s.X != dp[now][j - 1].X)
                        dfs(0, (s.X << m | sta[i + 1]) & (ttl << m | ttl), s.Y);
                }
                now ^= 1;
            }
            int ans = 0;
            for (int i = 0; i < dp[now].size(); i ++) {
                umax(ans, dp[now][i].Y);
            }
            cout << ans << endl;
        }
        return 0;
    }
  • 相关阅读:
    January 25th, 2018 Week 04th Thursday
    January 24th, 2018 Week 04th Wednesday
    January 23rd, 2018 Week 04th Tuesday
    January 22nd, 2018 Week 04th Monday
    January 21st, 2018 Week 3rd Sunday
    January 20th, 2018 Week 3rd Saturday
    January 19th, 2018 Week 3rd Friday
    January 18th, 2018 Week 03rd Thursday
    January 17th, 2018 Week 03rd Wednesday
    January 16th, 2018 Week 03rd Tuesday
  • 原文地址:https://www.cnblogs.com/jklongint/p/4679140.html
Copyright © 2011-2022 走看看