HDOJ 5965 扫雷 【DP】

来源:互联网 发布:php app接口开发步骤 编辑:程序博客网 时间:2024/06/05 00:12

扫雷

TimeLimit: 2000/1000 MS (Java/Others)    Memory Limit:65536/65536 K (Java/Others)
Total Submission(s): 1806    Accepted Submission(s): 491

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



题意:略

思路:用dp[i][j][k]表示考虑到第i列,且第i列和第i-1列一共有j个地雷,第i行有k个地雷的方案数。用num[i]来表示某一行放置i个地雷有多少情况。

那么可以写出状态转移方程:

dp[i][j][k]=dp[i-1][pre_j][pre_k]*ans[k](pre_j,pre_k为前一列的状态量)

分析方程:

  1. 第i列有k个地雷。
  2. 第i-1列有j-k(pre_k)个地雷。
  3. 第i-2列有pre_j-pre_k个地雷。

可以得到关系式:

  1. pre_k=j-k.
  2. pre_j+k=a[i-1] (第i-1列周围的地雷数)

然后三重循环状态转移,且将最后一列所有可能的情况累加即可。(注意特殊情况的特判)

PS:此题这种做法有点卡时限,需要多提交几次。

可能的优化方法TUT。。。

把数组开小,开到刚刚好,如果dp[][][]的后两维都开到10,就一定TLE。


#include <cstdio>#include <iostream>#include <vector>#include <string>#include <cstring>#include <algorithm>using namespace std;#define mst(a,b) memset((a),(b),sizeof(a))#define f(i,a,b) for(int i=(a);i<=(b);++i)#define rush() int T;scanf("%d",&T);while(T--)typedef long long ll;const int maxn= 10005;const int mod = 1e8+7;const int INF = 0x3f3f3f3f;const double eps = 1e-6;//dp[i][j][k]表示到第i列,这一列的和前一列的地雷数为j个,并且这一列的地雷数为k个的方案数int a[maxn];char s[maxn];ll dp[maxn][5][3];int num[3]={1,2,1};int main(){    rush()    {        scanf("%s",s);        int len=strlen(s);        int flag=0;        for(int i=1;i<=len;i++)        {            a[i]=s[i-1]-'0';            if((i==1||i==len)&&a[i]>4) flag=1;            if(a[i]>6) flag=1;        }        if(flag)        {            puts("0");            continue;        }        if(len==1)        {            if(a[1]<=2) printf("%d\n",num[a[1]]);            else puts("0");            continue;        }        mst(dp,0);        for(int i=0;i<=2;i++)        {            if(a[1]>=i)                dp[1][i][i]=num[i];            else dp[1][i][i]=0;        }        for(int i=2;i<=len;i++)        for(int j=0;j<=4;j++)        for(int k=0;k<=2&&k<=j;k++)        {            int pre_j=a[i-1]-k;            int pre_k=j-k;            if(pre_j>=0&&pre_k>=0&&pre_j>=pre_k)            {                dp[i][j][k]=num[k]*dp[i-1][pre_j][pre_k];                dp[i][j][k]%=mod;            }        }        ll ans=0;        for(int i=0;i<=a[len]&&i<=2;i++)        {            ans+=dp[len][a[len]][i];            ans%=mod;        }        printf("%I64d\n",ans);    }    return 0;}