GalaxyOJ-902 Mine

题目描述

有一个 1 维的扫雷游戏,每个格子用表示有雷,用 0/1/2 表示无 雷并且相邻格子中有 0/1/2 个雷。 给定一个仅包含?、、0、1、2 的字符串 S,问有多少种方法将所 有的?改为/0/1/2 使其合法。
输入一个字符串S,输出一行一个整数表示答案,对10^9+7取模。

输入

?1?

输出

2

数据范围

对于30%的数据,|S|<=20。
对于60%的数据,|S|<=1000。
对于100%的数据,|S|<=10^6。

目前对于自己没有思路的题暂时使用copy代码加自己的注释和文末总结吧.的确智商捉急哈
源自CSDN题解
老哥代码写的很简洁明了啦

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
long long n,ans,f[1000005][10];
char a[1000005];

int main(){
    scanf("%s",a);
    n=strlen(a);
    if (a[0]=='*') f[0][4]=f[0][5]=1;//到1下一个是雷和下一个不是雷的可能都为1
    if (a[0]=='0') f[0][0]=1;//那么下一个必然不为雷的种数为1
    if (a[0]=='1') f[0][2]=1;//下一个必然为雷1
    if (a[0]=='2' || a[n-1]=='2') {puts("0"); return 0;}//由于在两端,最多周围只可能有一个雷
    if (a[0]=='?') f[0][0]=f[0][2]=f[0][4]=f[0][5]=1;//如果不确定,那么因为对于下一块,每一种可能的种数都加一
    for (int i=1; i<n; i++)
	{
        if (a[i]=='*' || a[i]=='?')//这个是雷
		{
            f[i][4]=f[i][5]=(f[i-1][2]+f[i-1][3]+f[i-1][4])%(1000000007);//这个是雷的种数是 上一个为1且下一个为雷的种数 加上 一个为2且下一个为雷的种数 加上 上一个为雷且下一个为雷的种数
        }
        if (a[i]=='0' || a[i]=='?')//这周围没有雷的种数是 上一个是1下一个不是雷的种数 + 上一个是0的种数
		{
            f[i][0]=(f[i-1][1]+f[i-1][0])%(1000000007);
        }
        if (a[i]=='1' || a[i]=='?')//这个是1的种数
		{
            f[i][2]=(f[i-1][1]+f[i-1][0])%(1000000007);//右边是雷 上一个不是雷且下一个不是雷的两种情况的种数之和
            f[i][1]=f[i-1][5];//左边是雷
        }
        if (a[i]=='2' || a[i]=='?')//两边都是雷
		{
            f[i][3]=f[i-1][5];//上一个是雷且下一个不是雷的种数
        }
    }
    n--;//0- (n-1)
    ans=(f[n][0]+f[n][1]+f[n][5])%(1000000007);//最后一个的下一个必然不可能为雷
    printf("%lld",ans);
}

/*
0   0(下一个不是雷)
1   1(下一个不是雷) 
2   1(下一个是雷) 
3   2(下一个是雷)
4   *(下一个是雷)
5   *(下一个不是雷)
*/

总体来看思路还是很明确的,第i个为哪一种可能的种数仅于上一个的种数有关系,DP的无后效性是指的一个之后吗???

posted @ 2022-08-13 20:14  qbning  阅读(45)  评论(0编辑  收藏  举报
描述