zoukankan      html  css  js  c++  java
  • ZOJ3697 Badwritten Number 恶心模拟状态压缩动态规划

    题意:给定一系列的数码管,这些数码管由3*3的图形构成,相邻的两个数码管紧挨着的一列是重叠的,现在问一共有多少种可能的情况。

    解法:将每个数字的可能的显示结果(能亮的地方假设都可以亮)保留起来,然后一个一个数码枚举,一个地方要注意就是相邻意味前面一个数码占用了某一个亮线,那么后面这个数码可以选择是否占用该亮线,而如果前面没用占用该亮线则后面的数码必须占用。使用f[i][j]表示到第i个字符,占用相邻列情况为j时的方案数。

    代码如下:

    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    
    int N, to[9] = {
        -1, 0, -1, 1, 2, 3, 4, 5, 6
    };
    char str[3][30000];
    char table[128];
    // 123, 72, 61, 109, 78, 103, 119, 73, 127, 111
    const int MOD = int(1e9)+7;
    const int MM[4] = {0, 8, 64, 72}; // 分别表示都不取,取上面的一根,取下面一根以及都取
    const int RR[4] = {0, 2, 16, 18};
    
    typedef long long LL;
    LL f[10005][4]; // 其中f[i][j]表示到第i个数字,前面占用了j状态时的方案数 
    
    struct NUM {
        char sta;
        void show() {
            for (int i = 0; i < 7; ++i) {
                printf("%d ", sta & (1 << i) ? 1 : 0);
            }
            puts("");
        } 
    }n[10005];
    
    void init() {
        for (int i = 0; i < N; ++i) {
            int l = i << 1, r = (i+1) << 1;
            for (int j = 0; j < 3; ++j) {
                for (int k = l; k <= r; ++k) {
                    int x = j * 3 + k - l;
                    if (str[j][k] != ' ' && str[j][k] != '\0') {
                        n[i].sta |= 1 << to[x];
                    }
                }
            }
        }
    }
    
    LL solve() {
        int t, h, flag = 0;
        memset(f, 0, sizeof (f));
        for (int i = 0; i < 4; ++i) {
            if ((n[0].sta & MM[i]) == MM[i]) { // 表示能够提供这样的一个选取方案
                if (table[n[0].sta&(~MM[3-i])]) {
                    f[0][i] = 1;
                    flag = 1;
                }
            }
        }
        if (!flag) return 0;
        for (int i = 1; i < N; ++i) {
            flag = 0;
            for (int j = 0; j < 4; ++j) {
                if ((n[i].sta & MM[j]) == MM[j]) {
                    t = n[i].sta & (~MM[3-j]);
                    for (int k = 0; k < 4; ++k) {
                        if (!f[i-1][k]) continue;
                        h = t & (~RR[k]); // 一定要亮的灯
                        if (table[h]) {
                            f[i][j] += f[i-1][k];
                            f[i][j] %= MOD;
                            flag = 1;
                        }
                        if (k == 1) {
                            h = t & (~RR[k]) | 1 << 1;
                            if (table[h]) {
                                f[i][j] += f[i-1][k];
                                f[i][j] %= MOD;
                                flag = 1;
                            }
                        } else if (k ==2) {
                            h = t & (~RR[k]) | 1 << 4;
                            if (table[h]) {
                                f[i][j] += f[i-1][k];
                                f[i][j] %= MOD;
                                flag = 1;
                            }
                        } else if (k == 3) {
                            h = t & (~RR[k]) | 1 << 1;
                            if (table[h]) {
                                f[i][j] += f[i-1][k];
                                f[i][j] %= MOD;
                                flag = 1;
                            }
                            h = t & (~RR[k]) | 1 << 4;
                            if (table[h]) {
                                f[i][j] += f[i-1][k];
                                f[i][j] %= MOD;
                                flag = 1;
                            }
                            h = t & (~RR[k]) | 1 << 1 | 1 << 4;
                            if (table[h]) {
                                f[i][j] += f[i-1][k];
                                f[i][j] %= MOD;
                                flag = 1;
                            }
                        }
                    }
                }
            }
            if (!flag) return 0;
        }
        int sp = ((n[N-1].sta>>3)&1) | ((n[N-1].sta>>5)&2);
        return f[N-1][sp];
    }
    
    int main() {
        table[123] = table[72] = table[61] = table[109] = table[78] = 1;
        table[103] = table[119] = table[73] = table[127] = table[111] = 1;
        int T;
        scanf("%d", &T);
        getchar();
        while (T--) {
            memset(n, 0, sizeof (n));
            scanf("%d", &N); // 表示有N个数字被书写
            getchar();
            for (int i = 0; i < 3; ++i) {
                memset(str[i], 0, sizeof (str[i]));
                gets(str[i]);
            }
            init();
            printf("%lld\n", solve());
        }
        return 0;    
    }
  • 相关阅读:
    sql server 获取本月的始末时间
    超时时间已到
    sql server定时自动备份
    创建连接服务器
    date制作电子时钟
    C#继承(三)
    C# Split分割
    Dom动态添加属性
    date制作电子时钟(二)
    全局遮罩 shade
  • 原文地址:https://www.cnblogs.com/Lyush/p/3065967.html
Copyright © 2011-2022 走看看