三维线性动态规划,只要这题理解了线性DP直接拿下!

279 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 4 天,点击查看活动详情

牛客小白月赛19 J题「火」皇家烈焰

题目描述:

帕秋莉掌握了一种火属性魔法 由于钟爱扫雷游戏,帕秋莉把自己图书馆前的走廊看作一个一维的扫雷地图,她制造了很多烈焰,排在这条走廊内 现在帕秋莉告诉你一部分烈焰的分布情况,请你告诉她可能的情况有多少种 对于一个格子,里面会有以下几种字符:

  • 0:这个格子没有烈焰,且其左右两个格子均没有烈焰
  • 1:这个格子没有烈焰,且其左右两个格子中只有一个烈焰
  • 2:这个格子没有烈焰,且其左右两个格子中均有烈焰
  • *:这个格子有烈焰
  • ?:未告诉你本格情况

输入描述: 一个字符串

输出描述: 输出一行,一个整数表示答案,对1e9+7取模

题解分析: 分析几维DP:首先这道题显然的dp题目,状态转移的时候,与前一位,当前位,后一位都有关系,所以开三维DP 即:f[i][0/1][0/1] 分别表示:f[前i位][当前位是否有雷][后一位是否有雷] (其中0表示没雷,1表示有雷)

初始化:f[0][0][0]=1,f[0][0][1]=1

分类讨论:

如果s[i]=0 ,那么代表,当前位,前一位,后一位均无雷

状态转移方程为:f[i][0][0]+=f[i-1][0][0]%mod

如果 s[i]=1 ,那么代表,当前位无雷,前一位有雷或者后一位有雷,

状态转移方程为:

​ 如果是前一位有雷,后一位无雷:f[i][0][0]+=f[i-1][1][0]%mod

​ 如果是前一位无雷,后一位有雷:f[i][0][1]+=f[i-1][0][0]%mod

如果s[i]=2 ,那么代表,当前位无雷,前一位和后一位均有雷

状态转移方程为:f[i][0][1]+=f[i-1][1][0]%mod

如果s[i]=*,那么代表,当前位有雷,前一位后一位不清楚

状态转移方程为:

​ 如果后一位无雷:f[i][1][0]+=(f[i-1][0][1]+f[i-1][1][1])%mod

​ 如果后一位有雷:f[i][1][1]+=(f[i-1][0][1]+f[i-1][1][1])%mod

如果s[i]=?,那么当前位置不知道,就需要讨论所有情况

​ 如果当前位有雷,下一位无雷:f[i][1][0]+=(f[i-1][0][1]+f[i-1][1][1])%mod

​ 如果当前位有雷,下一位有雷:f[i][1][1]+=(f[i-1][0][1]+f[i-1][1][1])%mod

​ 如果当前位无雷,下一位无雷:f[i][0][0]+=(f[i-1][0][0]+f[i-1][1][0])%mod

​ 如果当前位无雷,下一位有雷:f[i][0][1]+=(f[i-1][0][0]+f[i-1][1][0])%mod

输出:(f[n][1][0] + f[n][0][0]) % mod 即可

#include<bits/stdc++.h>
using namespace std;
const int N = 1000010;
const int mod = 1e9 + 7;
int f[N][2][2];
int main() {
    string s;
    cin >> s;
    s = " " + s;
    int n = s.size() - 1;
    f[0][0][0] = 1, f[0][0][1] = 1;
    for (int i = 1; i <= n; i++) {
        if (s[i] == '0') f[i][0][0] += f[i - 1][0][0] % mod;
        else if (s[i] == '1') {
            f[i][0][0] += f[i - 1][1][0] % mod;
            f[i][0][1] += f[i - 1][0][0] % mod;
        } else if (s[i] == '2') f[i][0][1] += f[i - 1][1][0] % mod;
        else if (s[i] == '*') {
            f[i][1][0] += (f[i - 1][0][1] + f[i - 1][1][1]) % mod;
            f[i][1][1] += (f[i - 1][0][1] + f[i - 1][1][1]) % mod;
        } else if (s[i] == '?') {
            f[i][1][0] += (f[i - 1][0][1] + f[i - 1][1][1]) % mod;
            f[i][1][1] += (f[i - 1][0][1] + f[i - 1][1][1]) % mod;
            f[i][0][0] += (f[i - 1][0][0] + f[i - 1][1][0]) % mod;
            f[i][0][1] += (f[i - 1][0][0] + f[i - 1][1][0]) % mod;
        }
    }
    cout << (f[n][0][0] + f[n][1][0]) % mod << endl;
    return 0;
}