HDU5965 扫雷 —— dp递推

题目链接: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 100000007

using 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);
    }

}


 

posted on 2017-03-24 19:42  h_z_cong  阅读(146)  评论(0编辑  收藏  举报

导航