zoukankan      html  css  js  c++  java
  • P2704 [NOI2001]炮兵阵地

    P2704 [NOI2001]炮兵阵地

    题目链接

    ​ 状压DP。

    ​ 这个炮可以打到上面两行,这个点卡了我很久,我一开始就压一行的状态,发现会无线套娃:当前行可能会打到上两行,你还不能只判断当前行与上一行是否匹配,还得判断上两行;判了上一行还要判断上一行的上两行。。。。

    ​ 为了解决这个问题,我们可以直接把两行的状态放到一个数组里,这样问题就解决了。

    ​ 转移方程:(dp[i][F][G] = max(calc(F) + dp[i - 1][G][LG]))(F)为当前行的状态,(G)为上一行的状态,(LG)为上两行的状态, (calc(F))是计算当前行的炮兵数。

    #include <bits/stdc++.h>
        
    using namespace std;
        
    inline long long read() {
        long long s = 0, f = 1; char ch;
        while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
        for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
        return s * f;
    }
        
    const int N = 105, M = 2000;
    int n, m, ans;
    int num[N], c[N][M], S[N][M], mat[N][N], dp[N][M][M];
    
    int judge(int x, int s) {
        if((s << 1) & s) return 0;
        if((s << 2) & s) return 0;
        if((s >> 1) & s) return 0;
        if((s >> 2) & s) return 0;
        for(int i = 0;i < m; i++) {
            int tmp = (s >> i) & 1;
            if(mat[x][m - i] == 0 && tmp == 1) return 0;
        }
        return 1;
    }
    
    void make_pre_S() {
        for(int i = 1;i <= n; i++) 
            for(int j = 0;j <= (1 << m) - 1; j++) 
                if(judge(i, j)) S[i][++num[i]] = j;
    }
    
    int calc(int s) {
        int res = 0;
        for(int i = 0;i < m; i++) 
            if((s >> i) & 1) res++;
        return res;
    }
    
    int match(int s1, int s2) {
        if(s1 & s2) return 0;
        return 1;
    }
    
    int main() {
    
        n = read(); m = read();
        for(int i = 1;i <= n; i++) {
            string ch; cin >> ch;
            for(int j = 1;j <= m; j++) 
                if(ch[j - 1] == 'P') mat[i][j] = 1;
        }
    
        make_pre_S(); // 预处理出所有合法状态
        num[0] = 1;
        for(int i = 1;i <= num[1]; i++) 
            dp[1][S[1][i]][0] = calc(S[1][i]);
          for(int i = 2;i <= n; i++) {
            for(int s1 = 1;s1 <= num[i]; s1++) {
                int F = S[i][s1];
                for(int s2 = 1;s2 <= num[i - 1]; s2++) {
                    int G = S[i - 1][s2];
                    for(int s3 = 1; s3 <= num[i - 2]; s3++) {
                        int LG = S[i - 2][s3];
                        if(match(F, G) && match(F, LG) && match(G, LG)) {
                            dp[i][F][G] = max(dp[i][F][G], calc(F) + dp[i - 1][G][LG]);
                        }
                    }
                }
            }
        }
    
        for(int s1 = 1;s1 <= num[n]; s1++) {
            int F = S[n][s1];
            for(int s2 = 1; s2 <= num[n - 1]; s2++) {
                int G = S[n - 1][s2];
                ans = max(ans, dp[n][F][G]);
            }
        }
    
        printf("%d", ans);
        
    
        return 0;
    }
    
    
  • 相关阅读:
    有向无环图单源最短路径问题
    linux下程序编译出错解决方法
    Ceres入门笔记
    Java 中的数据结构类 Vector 和 ArrayList
    102. Binary Tree Level Order Traversal
    104. Maximum Depth of Binary Tree
    101. Symmetric Tree
    100. Same Tree
    490. The Maze
    骑士游历问题
  • 原文地址:https://www.cnblogs.com/czhui666/p/13641690.html
Copyright © 2011-2022 走看看