Date:2019/10/13
Degree of difficulty:Universal
Original question:P2327 [SCOI2005]扫雷
- 原题与改编
10.13月考【爆零祭】
T103466 新扫雷游戏
怎么说呢,作为一个没有经历过多少比赛的蒟蒻,今天的考试还是有点虚的,毕竟没有多少做题经验,有些步骤还是有些生疏,做题时候也有些慌乱,没有把握好节奏。
再有一点,就是生活经验不是很多,连扫雷都没玩过,一个坑竟然不能放3个雷??
所以要把这种有关游戏的题目和中国传统的游戏方式(与现在学习知识有关的)多看看看
杨老师说:与其蜻蜓点水,每个题20、30分,还不如好好的沉下心来,AC一道题
目录
- 本题思路
- 数组递推
- 深搜
- 一些学会的东西
Ox00 本题思路
这道题我们很快的就能知道
右边一列的每一个数是等于左边相邻的3列的和的
所以得到公式b[i]=a[i]+a[i-1]+a[i+1];
但是我们现在已知的东西是右边的数,左边的的前两列,所以问题就变成了求第三列的数
移项易得a[i]=b[i]-a[i-1]-a[i+2];
所以用这个递推公式
但注意!!!
每个格子只能放1~2个雷 (没玩过扫雷哭晕)
所以第一个格子只有三种情况
1. 有0个雷,那么第一列第一行第二行都是0;0+0=0
2. 有一个雷
2.1 第一列第一行是1,第二行是0;1+0=1
2.2 第一列第一行是0,第二行1;0+1=1
3. 有两个雷,那么第一列第一行第二行都是1;1+1=2
所以每次加减以后都要判断它是不是1或者2,成功剪枝;
还要在最后一个点的时候判断a[n-1][1]+a[n][1]==a[n][2]
如下
for(int i = 3; i <= n; i++){//dfs程序
a[i][1] = a[i-1][2] - a[i-1][1] - a[i-2][1];
if(a[i][1] > 1 || a[i][1] < 0){
fl = 1 ; break;
}
}
if(fl==0&&a[n-1][1]+a[n][1]==a[n][2])
vie++;
Ox01 深搜
dfs的思路就是每个格子只能放0个或者1个
所以搜索就好
但是我这个剪枝没有剪好
所以先不放代码了
(未完待续)
Ox02 DP
这道题也可用DP做
详情请见
这道题根据我的老师的思路是定义一个三维数组dp[i][j][k]
来做动态规划
其中j表示第i行的地雷数,k表示第i+1行的地雷数,
而dp[i][j][k]代表当前的组数。
初始条件为dp[0][0][0]=dp[0][0][1]=1
即第1行为0个或为1个时都有一种可能。然后根据第i行给的ai来进行动态转移。
- 若ai==0,则i-1,i,i+1必须分别对应 0,0,0,
所以这种情况下转移方程:dp[i][0][0]=dp[i-1][0][0]
。 - 若ai==3,则i-1,i,i+1必须分别对应 1,1,1
所以这种情况下转移方程dp[i][1][1]=dp[i-1][1][1]
。 - 若ai==1,则分为三种情况
i-1 i i+1 动转方程
1 0 0 dp[i][0][0]=dp[i-1][1][0]
0 1 0 dp[i][1][0]=dp[i-1][0][1]
0 0 1 dp[i][0][1]=dp[i-1][0][0]
- 若ai==2,也是三种情况
i-1 i i+1 动转方程
1 1 0 dp[i][1][0]=dp[i-1][1][1]
0 1 1 dp[i][1][1]=dp[i-1][0][1]
1 0 1 dp[i][0][1]=dp[i-1][1][0]
记得开全局变量因为这样不合法的转移就全部是0了。 在最后输出的答案为dp[n][1][0]+dp[n][0][0],这是第n行有地雷或无地雷的数量的总和(n+1不能取)。 大概就是这样详情请见代码,我觉得挺简洁的。
#include <iostream>
#include <vector>
#include <cstring>
#include <queue>
using namespace std;
int n,a[10005];
int dp[10005][2][2];
int main(){
cin>>n;
for (int i=1;i<=n;i++) cin>>a[i];//读入数据
dp[0][0][0]=dp[0][0][1]=1;//初始化
for (int i=1;i<=n;i++){//状态转移
if (a[i]==0){
dp[i][0][0]=dp[i-1][0][0];
}
if (a[i]==3){
dp[i][1][1]=dp[i-1][1][1];
}
if (a[i]==2){
dp[i][1][1]=dp[i-1][0][1];
dp[i][1][0]=dp[i-1][1][1];
dp[i][0][1]=dp[i-1][1][0];
}
if (a[i]==1){
dp[i][0][1]=dp[i-1][0][0];
dp[i][1][0]=dp[i-1][0][1];
dp[i][0][0]=dp[i-1][1][0];
}
}
cout<<dp[n][1][0]+dp[n][0][0];
}
//作者: momo5440 更新时间: 2019-03-20 23:37
OxFF 学到的一些东西
- 输入输出的写法
freopen("XX(文件名).in","r",stdin);//r is read
freopen("XX(文件名).out","w",stdout);// w is write
看注释会记得牢一点
2. 扫雷一个格子放0或者1个
3. 数组不清零,爆零两行泪