题解: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;
}

尾附

posted @ 2025-07-21 12:54  KukCair  阅读(27)  评论(0)    收藏  举报