Wannafly挑战赛10 B 小H和密码【二维dp*好题】

链接:https://www.nowcoder.com/acm/contest/72/B
来源:牛客网
题目描述
小H在击败怪兽后,被一个密码锁挡住了去路
密码锁由N个转盘组成,编号为1~N,每个转盘有M个位置,每个位置上要么有一个小写字母,要么没有任何字符。一个密码能被转盘表示出,当且仅当指定每个转盘上面的某一个位置,然后将这些位置按照所属的转盘编号顺次连接(空位置直接忽略),可以得到这个密码
小H并没有得到任何线索,因此只能猜,她一共猜了Q次,但并不知道自己猜的密码能否被表示出来,于是她向你求助
输入描述:
第1行,三个整数N,M,Q
第2~N+1行,每行一个长度为M的字符串,依次表示每个转盘上的字符
第N+2~N+Q+1行,每行一个长度不超过10000的字符串,表示小H猜的密码
2≤N,Q≤300,2≤M≤27,同一个转盘上每种字符最多出现一次
输出描述:
输出Q行,每行都是YES或NO,依次表示小H猜的每个字符串能否被表示出
示例1
输入
3 2 3
a#
ab
bc
aa
bb
ba
输出
NO
YES
NO
备注:
“#”:表示空字符

分析:空间太大,字典树无力,dp正解,把暴力抽象成矩阵形式,之前见过一道类似的。预处理每行哪些字符存在,dp[i][j]:真假表示(给定的串)第i行(查询输入的串)前j个字符匹配的状态。
匹配时方程:dp[i][j + 1] |= dp[i - 1][j];
空格时方程:dp[i][j] |= dp[i - 1][j];

#include 
using namespace std;

const int MAXN = 310;
char str[MAXN][MAXN], ch[10010];
int mapp[MAXN][MAXN], dp[MAXN][MAXN];

int main() {
    int n, m, q;
    scanf("%d %d %d", &n, &m, &q);
    for(int i = 1; i <= n; ++i) {
        getchar();
        scanf("%s", str[i]);
        for(int j = 0; j < m; ++j) {
            mapp[i][str[i][j]]++;
        }
    }
    while(q--) {
        getchar();
        scanf("%s", ch);
        int len = strlen(ch);
        if(len > n) puts("NO");
        else {
            memset(dp, 0, sizeof(dp));
            dp[0][0] = 1;
            for(int i = 1; i <= n; ++i) {
                for(int j = 0; j <= len; ++j) {
                    if(j < len && mapp[i][ch[j]]) dp[i][j + 1] |= dp[i - 1][j];
                    if(mapp[i]['#']) dp[i][j] |= dp[i - 1][j];
                }
            }
            if(dp[n][len]) puts("YES");
            else puts("NO");
        }
    }
    return 0;
}

你可能感兴趣的:(ACM模板,普通dp)