扫雷
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为前一列的状态量)
分析方程:
- 第i列有k个地雷。
- 第i-1列有j-k(pre_k)个地雷。
- 第i-2列有pre_j-pre_k个地雷。
可以得到关系式:
- pre_k=j-k.
- 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;
}