扫雷
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 718 Accepted Submission(s): 169
该游戏的界面是一个矩阵,矩阵中有些格子中有一个地雷,其余格子中没有地雷。 游戏中,格子可能处于己知和未知的状态。如果一个己知的格子中没有地雷,那么该 格子上会写有一个一位数,表示与这个格子八连通相邻的格子中地雷总的数量。
现在,晨晨和小璐在一个3行N列(均从1开始用连续正整数编号)的矩阵中进 行游戏,在这个矩阵中,第2行的格子全部是己知的,并且其中均没有地雷;而另外 两行中是未知的,并且其中的地雷总数量也是未知的。
晨晨和小璐想知道,第1行和第3行有多少种合法的埋放地雷的方案。
每组数据由一行仅由数字组成的长度为N的非空字符串组成,表示矩阵有3行N 列,字符串的第i个数字字符表示矩阵中第2行第i个格子中的数字。
保证字符串长度N <= 10000,数据组数<= 100。
2 22 000
6 1
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 <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#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<<endl;
else if(a[1]==0||a[1]==2)cout<<1<<endl;
else cout<<0<<endl;
continue;
}//初始化第一列状态
if(a[1]==0){
dp[1][0][0]=1;
}
else if(a[1]==1){
dp[1][0][1]=2;
dp[1][1][0]=1;
}
else if(a[1]==2){
dp[1][0][2]=1;
dp[1][1][1]=2;
dp[1][2][0]=1;
}
else if(a[1]==3){
dp[1][2][1]=2;
dp[1][1][2]=1;
}
else if(a[1]==4){
dp[1][2][2]=1;
}//
for(int i=2;i<=len;i++){//if(i==9)cout<<dp[9][1][0]<<endl;
for(int j=0;j<=2;j++){
for(int k=0;k<=2;k++){
if(dp[i-1][j][k]&&a[i]>=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<<sum<<endl;
}
return 0;
}