P7724 远古档案馆(Ancient Archive)题解
思路
考虑分情况讨论。
我们可以枚举出有一个空格、两个空格、三个空格、全是空格的情况,再跑DFS,可以使用记忆化搜索进行优化。
实现
2.1:编写判断函数
为了判断目前的状态与我们需要的状态是否一致,可以直接写一个 \(\texttt{bool}\) 函数判断:
bool check(int x,int y,int z,int p){
if(x!=b[1][1]){
return false;
}
if(y!=b[1][2]){
return false;
}
if(z!=b[2][1]){
return false;
}
if(p!=b[2][2]){
return false;
}
return true;
}
如果有一个格子不同我们可以直接return false
,如果没有成功return false
(即没有格子不同),那就可以return true
。
因此我们可以在dfs
函数中写出如下的代码:
if(check(x1,y1,x2,y2)){
puts("Yes");
exit(0);//强行结束整个程序
}
2.2 枚举只有一个格子为空的情况
我们用 \(k\) 表示空格子的数量。
if(k==1){
if(y1==0){
if(!c[0][x1][x2][y2]){
c[0][x1][x2][y2]=1;
dfs(0,x1,x2,y2);
}
if(!c[x1][y2][x2][0]){
c[x1][y2][x2][0]=1;
dfs(x1,y2,x2,0);
}
return;
}
if(x1==0){
if(!c[y1][0][x2][y2]){
c[y1][0][x2][y2]=1;
dfs(y1,0,x2,y2);
}
if(!c[x2][y1][0][y2]){
c[x2][y1][0][y2]=1;
dfs(x2,y1,0,y2);
}
return;
}
if(x2==0){
if(!c[0][y1][x1][y2]){
c[0][y1][x1][y2]=1;
dfs(0,y1,x1,y2);
}
if(!c[x1][y1][y2][0]){
c[x1][y1][y2][0]=1;
dfs(x1,y1,y2,0);
}
return;
}
if(y2==0){
if(!c[x1][0][x2][y1]){
c[x1][0][x2][y1]=1;
dfs(x1,0,x2,y1);
}
if(!c[x1][y1][0][x2]){
c[x1][y1][0][x2]=1;
dfs(x1,y1,0,x2);
}
return;
}
}
我们可以枚举出空的格子,对于每一种情况,可以证明有两种移动方式,我们只要对每种情况都枚举出来判断是否走过这个状态(记忆化搜索的精髓)。如果可以将记忆化数组修改再DFS这个新出现的状态。
同样的,我们可以写出有两个格子空、三个格子空情况。
2.3 四个格子空的情况怎么处理?
四个格子空的时候,我们可以在dfs
函数的最后写上这样一段特判:
if(k==4){
if(!c[0][0][0][0]){
c[0][0][0][0]=1;
dfs(0,0,0,0);
}
return;
}
把四个格子都空的情况标记了,如果最终数组不是四个空格(即check
函数没有返回true
)就会return
掉,输出No
。
2.4 没有格子空的情况怎么处理?
我们可以把check
函数放在dfs
函数的处理部分前面,如果check
函数返回false
,那么程序就会往下执行,但是我们并没有判断 \(k=0\) 的情况,程序就会直接return
掉,输出No
。
2.5 主函数
for(int i=1;i<=2;i++){
for(int j=1;j<=2;j++){
a[i][j]=read();
if(a[i][j]==0){
k++;
}
}
}
for(int i=1;i<=2;i++){
for(int j=1;j<=2;j++){
b[i][j]=read();
}
}
dfs(a[1][1],a[1][2],a[2][1],a[2][2]);
puts("No");
读入一个二维数组 \(a\) 表示最初的状态,用二维数组 \(b\) 表示最终的状态,把初始状态放进dfs
函数处理。如果没有输出Yes
(即没有exit(0)
)就输出No
。
AC Code
各部分代码已经在文中详细阐述。
AC记录
赛时AC记录