题解:P1312 [NOIP 2011 提高组] Mayan 游戏
基本思路
首先观察数据范围,\(n\) 顶顶到 \(5\),整个棋盘也最多有 \(35\) 个块,这你不搜???
直接搜每一次动哪个块,下落和消除直接模拟。
代码
(我这里把棋盘倒过来了,第一行是底部,行列从 \((1,1)\) 开始,横纵坐标也是反的。)
- 下落
判断每个块上方是否为空,空就往上找,不然让其挪到当前块。
void fall(){
for(int i = 1; i <= 7; i++){
for(int j = 1; j <= 5; j++){
for(int k = 1; k <= 7 - i && !p[i][j]; k++){
/* 其实这个 for 等价于
while(!p[i][j]) k++, p[i][j] = p[i + k][j], p[i + k][j] = 0; */
p[i][j] = p[i + k][j];
p[i + k][j] = 0;
}
}
}
}
- 消除
每当遇到符合要求的都标记一遍,切不可直接删(如图 \(5\))。
以及删除时会带来连锁反应,用的时候得判断是否删完了,弄个 while 就完了。
bool del(){
int fl = 0;
memset(f, 0, sizeof f);
/*行*/
for(int i = 1; i <= 7; i++){
for(int j = 1; j <= 3; j++){
if(!p[i][j]) continue;
if(p[i][j] == p[i][j + 1] && p[i][j] == p[i][j + 2])
f[i][j] = f[i][j + 1] = f[i][j + 2] = fl = 1;
}
}
/*列*/
for(int i = 1; i <= 5; i++){
for(int j = 1; j <= 5; j++){
if(!p[i][j]) continue;
if(p[i][j] == p[i + 1][j] && p[i][j] == p[i + 2][j])
f[i][j] = f[i + 1][j] = f[i + 2][j] = fl = 1;
}
}
for(int i = 1; i <= 7; i++){
for(int j = 1; j <= 5; j++){
if(f[i][j]) p[i][j] = 0;
}
}
fall(); // 删完了一定要落下,不能留空
return fl;
}
- dfs
虽然看起来很长,但其实就是直接搜。
void dfs(int step){
if(step > n){
for(int i = 1; i <= 7; i++)
for(int j = 1; j <= 5; j++)
if(p[i][j]) return; // 有没有消除的就不成立
for(int i = 1; i <= n; i++)
cout << path[i].y - 1 << ' ' << path[i].x - 1 << ' ' << path[i].g << '\n'; // -1 是因为我行列是从(1,1) 开始的,先y后x是因为我一开始就反了(懒得改)
exit(0);
}
int a[8][8];
for(int i = 1; i <= 7; i++)
for(int j = 1; j <= 5; j++)
a[i][j] = p[i][j]; // 保存当前这步的棋盘状态,要回溯
for(int j = 1; j <= 5; j++){
for(int i = 1; i <= 7; i++){
if(!p[i][j]) continue; // !!!空的不能操作!!!重点!!!
if(j != 5){ // →
path[step] = {i, j, 1};
swap(p[i][j + 1], p[i][j]);
fall();
while(del());
dfs(step + 1);
for(int i = 1; i <= 7; i++)
for(int j = 1; j <= 5; j++)
p[i][j] = a[i][j];
}
if(j != 1 && !p[i][j - 1]){ // ←
/*!p[i][j - 1]:这是一个小剪枝,若左边有块的话,让左边的块往右移字典序会更优*/
path[step] = {i, j, -1};
swap(p[i][j - 1], p[i][j]);
fall();
while(del());
dfs(step + 1);
for(int i = 1; i <= 7; i++)
for(int j = 1; j <= 5; j++)
p[i][j] = a[i][j];
}
}
}
}
- 完整代码
#include <bits/stdc++.h>
using namespace std;
struct node{
int x, y, g;
} path[6];
int n, p[8][8];
bool f[8][8];
void fall(){
for(int i = 1; i <= 7; i++){
for(int j = 1; j <= 5; j++){
for(int k = 1; k <= 7 - i && !p[i][j]; k++){
p[i][j] = p[i + k][j];
p[i + k][j] = 0;
}
}
}
}
bool del(){
int fl = 0;
memset(f, 0, sizeof f);
for(int i = 1; i <= 7; i++){
for(int j = 1; j <= 3; j++){
if(!p[i][j]) continue;
if(p[i][j] == p[i][j + 1] && p[i][j] == p[i][j + 2])
f[i][j] = f[i][j + 1] = f[i][j + 2] = fl = 1;
}
}
for(int i = 1; i <= 5; i++){
for(int j = 1; j <= 5; j++){
if(!p[i][j]) continue;
if(p[i][j] == p[i + 1][j] && p[i][j] == p[i + 2][j])
f[i][j] = f[i + 1][j] = f[i + 2][j] = fl = 1;
}
}
for(int i = 1; i <= 7; i++){
for(int j = 1; j <= 5; j++){
if(f[i][j]) p[i][j] = 0;
}
}
fall();
return fl;
}
void dfs(int step){
if(step > n){
for(int i = 1; i <= 7; i++)
for(int j = 1; j <= 5; j++)
if(p[i][j]) return;
for(int i = 1; i <= n; i++)
cout << path[i].y - 1 << ' ' << path[i].x - 1 << ' ' << path[i].g << '\n';
exit(0);
}
int a[8][8];
for(int i = 1; i <= 7; i++)
for(int j = 1; j <= 5; j++)
a[i][j] = p[i][j];
for(int j = 1; j <= 5; j++){
for(int i = 1; i <= 7; i++){
if(!p[i][j]) continue;
if(j != 5){
path[step] = {i, j, 1};
swap(p[i][j + 1], p[i][j]);
fall();
while(del());
dfs(step + 1);
for(int i = 1; i <= 7; i++)
for(int j = 1; j <= 5; j++)
p[i][j] = a[i][j];
}
if(j != 1 && !p[i][j - 1]){
path[step] = {i, j, -1};
swap(p[i][j - 1], p[i][j]);
fall();
while(del());
dfs(step + 1);
for(int i = 1; i <= 7; i++)
for(int j = 1; j <= 5; j++)
p[i][j] = a[i][j];
}
}
}
}
int main(){
cin >> n;
for(int i = 1; i <= 5; i++){
int x, k = 0;
while(cin >> x){
if(!x) break;
k++;
p[k][i] = x;
}
}
dfs(1);
cout << -1;
return 0;
}
尾附
![]()
本文来自博客园,作者:KukCair,转载请注明原文链接:https://www.cnblogs.com/KukCair/p/18995585

浙公网安备 33010602011771号