HDU5965 扫雷 —— dp递推

来源:互联网 发布:mac c库函数 编辑:程序博客网 时间:2024/06/15 00:18

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5965


题解:

1.

用a[]数组记录第二行的数字,用dp[]记录没一列放的地雷数。如果第一列的地雷数dp[1]已知,那么第二列的地雷数dp[2]可以确定了(因为a[1] = dp[0] + dp[1] + dp[2], dp[0]虚设), dp[2] = a[1] - dp[0] - dp[1];  于是第三列也已知:dp[3] = a[2] - dp[1] - dp[2]。 所以状态转移方程为:dp[i] = a[i-1] - dp[i-2] - dp[i-1]。

所以只需枚举第一列的地雷数就可以了。

在递推的过程中,每一列的地雷数必须在0~2的范围内,如果超出,则方案不符合,break; 

递推到第n+1个格子,如果dp[n+1] = 0, 则证明这种方案合法,更新答案。

2.

特殊点是i=0 和 i=n+1,因为可以假设他们存在,但却不能放地雷,所以可以通过他们判断方案是否合法。

突破口是i=1,因为i=1时,相邻边只有一条,知道自己,就可以知道相邻,然后一直递推下去。


代码如下:

#include<iostream>//hdu 5965 递推#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<algorithm>#define mod 100000007using namespace std;typedef long long LL;int dp[10005];char a[10005];int main(){    int t,i,j,ans,sum;    scanf("%d",&t);    while(t--)    {        scanf("%s",a+1);        int n = strlen(a+1);        for(i = 1; i<=n; i++)            a[i] -= '0';        ans = 0;        for(i = 0; i<=a[1] && i<=2; i++)//枚举第一列,i为第一列的地雷数        {            dp[1] = i;            for(j = 2; j<=n+1; j++)//从第二列开始递推            {                dp[j] = a[j-1]-dp[j-1]-dp[j-2];                if(dp[j]>2)                    break;            }            if(j==n+2 && dp[n+1] == 0)            {                sum = 1;                for(j = 1; j<=n; j++)                {                    if(dp[j]==1)                        sum = (sum*2)%mod;                }                ans = (ans + sum)%mod;            }        }        printf("%d\n",ans);    }}


0 0