题解 P1312 【Mayan游戏】
蒟蒻也能写出来的AC代码!(其实主要是为了纪念一遍AC这道题……)可能存在多余的地方和更好的剪枝,因此这份代码仅供参考,可以进一步优化。
这种数据范围贼小的题一看就是搜索。搜索的策略是:两重for循环枚举每一个点,对于一个点总是先考虑往右移(优先级更高),如果左边是0的话才考虑往左移(若左边是非0的话不必了,因为这种情况就是左边的点往右移,但它已经被研究过了)。移动完了就要消去,由于消去可能不止一次所以我们要用循环。
此外还要注意保存的方式。我是将数组完全复制到一个临时数组里。这样能保证原数组不会受到后续步骤消去的影响。
一些细节请看注释。
#include <iostream>
#include <cstdio>
using namespace std;
int n, a[10][10], temp, jie1[10], jie2[10], jie3[10];
void check(){
bool flag=true;
for(int i=1; i<=5; i++)
if(a[i][1])
flag = false;
if(flag){
for(int i=1; i<=n; i++)
printf("%d %d %d\n", jie1[i]-1, jie2[i]-1, jie3[i]);
exit(0);
}
}
bool func(){//消去及调整函数
bool s[10][10]={0}, flag=false;//flag标记有无进行消去
for(int i=1; i<=5; i++){
for(int j=1; a[i][j]; j++){
int k=i+1;//看x轴上以(i,j)为起点的块儿是否满足条件
for( ; k<=5; k++)
if(a[k][j]!=a[i][j])//找寻终点
break;
if(k-i>=3){//要是长度达标就标记下来,一会儿同时消去
for(int l=i; l<k; l++)
s[l][j] = true;
flag = true;
}
k = j+1;//看y轴上以(i,j)为起点的块儿是否满足条件
for( ; k<=7; k++)
if(a[i][j]!=a[i][k])
break;
if(k-j>=3){
for(int l=j; l<k; l++)
s[i][l] = true;
flag = true;
}
}
}
for(int i=1; i<=5; i++)
for(int j=1; j<=7; j++)
if(s[i][j])
a[i][j] = 0;//消去
if(!flag) return false;//要是没有消去就可以停下了
for(int i=1; i<=5; i++)
for(int j=1; j<=7; j++)
if(a[i][j]==0){//调整以防止悬空的出现
int k=j+1;
for( ; k<=7; k++)
if(a[i][k])
break;
a[i][j] = a[i][k];
a[i][k] = 0;
}
return true;
}
void dfs(int x){//以步数作为dfs的参数
for(int i=1; i<=5; i++){
for(int j=1; a[i][j]!=0; j++){
if(i!=5 && a[i][j]!=a[i+1][j] && a[i+1][j]!=0){//要是右边非0的话
int tem[10][10];
for(int ii=0; ii<=9; ii++)
for(int jj=0; jj<=9; jj++)
tem[ii][jj] = a[ii][jj];//复制到临时数组里
int tmp=a[i][j];
a[i][j] = a[i+1][j];
a[i+1][j] = tmp;
jie1[x] = i;
jie2[x] = j;
jie3[x] = 1;//保存这一步的答案
while(func()) ;//消去。要循环!
if(x==n) check();//要是步数够了就看看是否完全消去。
else dfs(x+1);
for(int ii=0; ii<=9; ii++)
for(int jj=0; jj<=9; jj++)
a[ii][jj] = tem[ii][jj];//优雅地回溯
}
if(i!=5 && a[i+1][j]==0){//要是右边为0的话
int tem[10][10];
for(int ii=0; ii<=9; ii++)
for(int jj=0; jj<=9; jj++)
tem[ii][jj] = a[ii][jj];
int k;
for(k=j-1; k>=1; k--)
if(a[i+1][k])
break;
k++;
a[i+1][k] = a[i][j];
a[i][j] = 0;
jie1[x] = i;
jie2[x] = j;
jie3[x] = 1;
for(int e=j; e<=6; e++){
a[i][e] = a[i][e+1];
a[i][e+1] = 0;
}
while(func()) ;
if(x==n) check();
else dfs(x+1);
for(int ii=0; ii<=9; ii++)
for(int jj=0; jj<=9; jj++)
a[ii][jj] = tem[ii][jj];
}
if(i!=1 && a[i-1][j]==0){//要是左边为0的话
int tem[10][10];
for(int ii=0; ii<=9; ii++)
for(int jj=0; jj<=9; jj++)
tem[ii][jj] = a[ii][jj];
int k;
for(k=j-1; k>=1; k--)
if(a[i-1][k])
break;
k++;
a[i-1][k] = a[i][j];
a[i][j] = 0;
jie1[x] = i;
jie2[x] = j;
jie3[x] = -1;
for(int e=j; e<=6; e++){
a[i][e] = a[i][e+1];
a[i][e+1] = 0;
}
while(func()) ;
if(x==n) check();
else dfs(x+1);
for(int ii=0; ii<=9; ii++)
for(int jj=0; jj<=9; jj++)
a[ii][jj] = tem[ii][jj];
}
}
}
}
int main(){
cin>>n;
for(int i=1; i<=5; i++){
int tmp = 0;
while(cin>>temp){
if(!temp) break;
a[i][++tmp] = temp;
}
}//读入数据,为了方便我们将左上角的设为(1, 1),在输出时减一即可
dfs(1);
cout<<"-1";//要是没有exit掉那就只能是无解了
return 0;
}
```cpp