HDU 5965 扫雷(递推)

扫雷

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 718    Accepted Submission(s): 169


Problem Description
扫雷游戏是晨晨和小璐特别喜欢的智力游戏,她俩最近沉迷其中无法自拔。
该游戏的界面是一个矩阵,矩阵中有些格子中有一个地雷,其余格子中没有地雷。 游戏中,格子可能处于己知和未知的状态。如果一个己知的格子中没有地雷,那么该 格子上会写有一个一位数,表示与这个格子八连通相邻的格子中地雷总的数量。
现在,晨晨和小璐在一个3行N列(均从1开始用连续正整数编号)的矩阵中进 行游戏,在这个矩阵中,第2行的格子全部是己知的,并且其中均没有地雷;而另外 两行中是未知的,并且其中的地雷总数量也是未知的。
晨晨和小璐想知道,第1行和第3行有多少种合法的埋放地雷的方案。
 

Input
包含多组测试数据,第一行一个正整数T,表示数据组数。
每组数据由一行仅由数字组成的长度为N的非空字符串组成,表示矩阵有3行N 列,字符串的第i个数字字符表示矩阵中第2行第i个格子中的数字。
保证字符串长度N <= 10000,数据组数<= 100。
 

Output
每行仅一个数字,表示安放地雷的方案数mod100,000,007的结果。
 

Sample Input

2 22 000
 

Sample Output

6 1
 

Source

2016年中国大学生程序设计竞赛(合肥)-重现赛(感谢安徽大学)




题意:


有一个3行N列的矩阵,第一行和第三行可以放置地雷,中间一行是数字,表示相邻9个格的地雷数,现在已知中间一行的数字,求可以放置地雷的方案。


我在第一眼看到这道题的时候就觉得是道DP题,因为数据给的太大,枚举不可能实现。所以刚开始就寻找这个问题的状态,我个人习惯先找状态,之后分析决策和阶段。

经过分析之后,找到状态dp[i][j][k],其中表示i表示第i列,k表示在第i列时放置k个地雷,j表示在第i+1列时应该放置的地雷数,  所以dp[i][j][k]表示在第i列放置k个地雷并且i+1列应该放置j个地雷时的最大方案数。

当我分析出来这个状态,求状态转移方程时发现,顺推更加简单,所以我把状态改成了递推式:把第二行的数据存入a数组里。

例如:当求出dp[i-1][j][k]时可以推出dp[i][a[i]-j-k][j]( 0<=j,k<=2,2>=a[i]-j-k>=0 ),

当j==1时:dp[i][a[i]-j-k][j]=dp[i-1][j][k]*2;(因为当j==1时,可以选择仅在第一行或第三行放置一个地雷)

当j==0 || j==2时: dp[i][a[i]-j-k][j]=dp[i-1][j][k]*1;

(其实我们中间可以发现一个规律:当第一列的地雷数确定时,第二列随之确定,同样,第三列的地雷数等于a[i]减去前两列的地雷数...同理,每一列的状态都是确定的。所以可以更简单一点的枚举第一列的地雷数。这道题就GG了。不过我懒得写了)


#include 
#include 
#include 
#include 
#include 
#define LL long long
#define mem(p,k) memset(p,k,sizeof(p));
using namespace std;
LL dp[10010][3][3];
char a[10010];
int main()
{
    int t;
    cin>>t;
        while(t--){
            scanf("%s",a+1);
            mem(dp,0);
            int len=strlen(a+1);
            for(int i=1;i<=len;i++)a[i]-=48;
            if(len==1){
                if(a[1]==1)cout<<2<=j+k&&a[i]-j-k<=2){


                            if(j==1){
                                dp[i][a[i]-j-k][j]+=dp[i-1][j][k]*2;
                                dp[i][a[i]-j-k][j]%=100000007;
                            }
                            else{
                                dp[i][a[i]-j-k][j]+=dp[i-1][j][k];
                                dp[i][a[i]-j-k][j]%=100000007;
                            }
                        }
                    }
                }


            }

            LL sum=0;

                for(int j=0;j<=2;j++){
                    sum+=dp[len][0][j];
                    sum%=100000007;
                }

            cout<




   

你可能感兴趣的:(DP,递推)