[SCOI2005]扫雷

题目描述
相信大家都玩过扫雷的游戏。那是在一个n\times mn×m的矩阵里面有一些雷,要你根据一些信息找出雷来。万圣节到了,“余”人国流行起了一种简单的扫雷游戏,这个游戏规则和扫雷一样,如果某个格子没有雷,那么它里面的数字表示和它8连通的格子里面雷的数目。现在棋盘是n\times 2n×2的,第一列里面某些格子是雷,而第二列没有雷,如下图:

由于第一列的雷可能有多种方案满足第二列的数的限制,你的任务即根据第二列的信息确定第一列雷有多少种摆放方案。

输入输出格式
输入格式:
第一行为N,第二行有N个数,依次为第二列的格子中的数。(1<= N <= 10000)

输出格式:
一个数,即第一列中雷的摆放方案数。

输入输出样例
输入样例#1:
2
1 1
输出样例#1:
2

可以正个问题分成四个子问题来看,为0时,1时,为2时,为3时,附近三格中雷的存在情况,开成四维的数组dp[i][j][k][l],分别存储当前行时,它的上一行,当前行,下一行雷的存在情况;
(1为存在雷,0为不存在雷)
1.为0时,说明当前行,当前行的上一行,当前行的下一行,都不能存在雷,所以dp[i][0][0][0]肯定是由 dp[i-1][1][0][0]和dp[i-1][0][0][0]转移而来;
2.为1时,说明当前行,当前行的上一行,当前行的下一行中,只有一个雷所以对于当前行存在三种情况 dp[i][0][1][0] ,dp[i][1][0][0]和dp[i][0][0][1]
a.对于dp[i][1][0][0]是由dp[i-1][1][1][0]和dp[i-1][0][1][0]转移而来
b.对于dp[i][0][1][0]是由dp[i-1][1][0][1]和dp[i-1][0][0][1]转移而来
c.对于dp[i][0][0][1]是由dp[i-1][1][0][0]和dp[i-1][0][0][0]转移而来
依此类推
3.为2时
dp[i][0][1][1] = dp[i-1][0][0][1] + dp[i-1][1][0][1];
dp[i][1][0][1] = dp[i-1][0][1][0] + dp[i-1][1][1][0];
dp[i][1][1][0] = dp[i-1][0][1][1] + dp[i-1][1][1][1];
4.为3时
dp[i][1][1][1] = dp[i-1][0][1][1] + dp[i-1][1][1][1];

再来看初始化,所有存在dp[i-1][1][][]的初始值都是不能存在的,因为这样对于第一行来说是不成立的所以只有0,0,0,0 0,0,1,0 0,0,0,1 0,0,1,1四种情况可行,但同时对于1,1,1,0 1,1,1,0又是不存在的所以,由dp方程可以得出用来转移他们的0,0,1,0和0,0,1,1都是不可行的所以初始化只有0,0,0,0 和0,0,0,1。同时在输出时,需要对最后一个格的情况进行特判输出。
最后一个为0时,输出dp[n][0][0][0],最后一个为1时输出dp[n][0][1][0]与dp[n][1][0][0],当最后一个为2时输出dp[n][1][1][0];
完结
代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
inline int read(){
    int x = 0;int f = 1;char c = getchar();
    while(c<'0'||c>'9'){
        if(c == '-')f = -f;
        c = getchar();
    }
    while(c<='9'&&c>='0'){
        x = x*10 + c - '0';
        c = getchar();
    }
    return x*f;
}
int n;
int dp[20000][2][2][2];
int a[20000];
int main(){
    n = read();dp[0][0][0][0] = 1;
    dp[0][0][0][1] = 1;
    for(int i = 1; i<=n; i++){
        a[i] = read();
        if(!a[i])dp[i][0][0][0] = dp[i-1][0][0][0] + dp[i-1][1][0][0];
        if(a[i] == 1){
        dp[i][1][0][0] = dp[i-1][0][1][0] + dp[i-1][1][1][0];
        dp[i][0][1][0] = dp[i-1][0][0][1] + dp[i-1][1][0][1];
        dp[i][0][0][1] = dp[i-1][0][0][0] + dp[i-1][1][0][0];	
        }
        else if(a[i] == 2){
            dp[i][0][1][1] = dp[i-1][0][0][1] + dp[i-1][1][0][1];
            dp[i][1][0][1] = dp[i-1][0][1][0] + dp[i-1][1][1][0];
            dp[i][1][1][0] = dp[i-1][0][1][1] + dp[i-1][1][1][1];
        }
        else if(a[i] == 3){
            dp[i][1][1][1] = dp[i-1][0][1][1] + dp[i-1][1][1][1];
        }
    }
    if(!a[n])printf("%d",dp[n][0][0][0]);
    else if(a[n] == 1)printf("%d",dp[n][1][0][0] + dp[n][0][1][0]);
    else if(a[n] == 2)printf("%d",dp[n][1][1][0]);
    return 0;
} 
posted @ 2018-12-09 21:18  Euplectella  阅读(158)  评论(0编辑  收藏  举报