ZOJ-3697 Bad-written 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;    
}

 

posted @ 2013-05-07 23:06  沐阳  阅读(421)  评论(0编辑  收藏  举报