洛谷 P1312 Mayan游戏
题目传送门
大模拟,用的bfs,完全按照题目描述做即可,其实本题用dfs要更好写.我的做法有点缺陷,但是不知道在哪里,不开\(O_2\)优化会T一个点.
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
using namespace std;
int n,a[10][10],oi,f_step;
string f_ans;//最后答案
map<string,int> p;//到当前状态的步数
map<string,bool> vis;//bfs用
map<string,string> ans;//到当前的状态的过程
queue<string> w;
inline bool check(string l) {//检查是否到了全部消掉的状态
for(int i = 0;i < l.length(); i++)
if(l[i] != '0') return 0;
return 1;
}
inline bool _compare(string l) {//更新答案
string u = ans[l];
for(int i = 0;i < min(u.length(),f_ans.length()); i++) {
int s1,s2;
s1 = u[i] - '0';
s2 = f_ans[i] - '0';
if((i + 1) % 3 == 0) {
if(s1 > s2) return 1;
if(s1 < s2) return 0;
}
else {
if(s1 < s2) return 1;
if(s1 > s2) return 0;
}
}
return 1;
}
inline void update_answer(string l) {
if(_compare(l)) {
f_step = p[ans[l]];
f_ans = ans[l];
}
}
inline string chuli(string l) {//移动方块后,处理能消除的块及让悬空的块落下去
int s[10][10],len = -1;
bool flag[10][10],oo = 0;
memset(flag,0,sizeof(flag));
for(int i = 0;i <= 6; i++) {
for(int j = 0;j <= 4; j++) {
s[i][j] = l[++len] - '0';
}
}
while(true) {
memset(flag,0,sizeof(flag));
oo = 0;
for(int i = 0;i <= 6; i++) {
for(int j = 0;j <= 4; j++){
if(s[i][j] == 0)
continue;
else {
int pp = i;
while(true) {
if(s[pp-1][j] != 0) break;
if(pp == 0) break;
s[pp-1][j] = s[pp][j];
s[pp][j] = 0;
pp--;
}
}
}
}
for(int i = 0;i <= 6; i++) {
for(int j = 0;j <= 4; j++) {
if(s[i][j] == 0) continue;
if(s[i][j] == s[i][j+1] && s[i][j] == s[i][j+2] && s[i][j] != 0)
flag[i][j] = flag[i][1+j] = flag[i][j+2] = 1,oo = 1;
if(s[i][j] == s[i+1][j] && s[i][j] == s[i+2][j] && s[i][j] != 0)
flag[i][j] = flag[i+1][j] = flag[i+2][j] = 1,oo = 1;
}
}
for(int i = 0;i <= 6; i++) {
for(int j = 0;j <= 4; j++)
if(flag[i][j])
s[i][j] = 0;
}
if(oo == 0) break;
}
len = -1;
for(int i = 0;i <= 6; i++)
for(int j = 0;j <= 4; j++)
l[++len] = char(s[i][j] + 48);
return l;
}
inline string bj(string x1,string x2) {//只有在当前走的答案比已知的答案最优才会更新(最优性剪枝)
for(int i = 0;i < min(x1.length(),x2.length()); i++) {
int s1,s2;
s1 = x1[i] - '0';
s2 = x2[i] - '0';
if((i + 1) % 3 == 0) {
if(s1 > s2) return x1;
if(s1 < s2) return x2;
}
else {
if(s1 < s2) return x1;
if(s1 > s2) return x2;
}
}
return x2;
}
inline void bfs() {
while(!w.empty()) {
string u = w.front();
w.pop();
vis[u] = 0;
if(p[u] >= n + 1) continue;
for(int i = 0;i < 35; i++) {
int x = i / 5;
int y = i % 5;
int step = p[u];
if(u[i] == '0') continue;
for(int k = 1;k >= -1; k -= 2) {
string l = u;
if(y == 4 && k == 1) continue;
if(y == 0 && k == -1) continue;
if(k == 1 && l[i] == l[i+1]) continue;
if(k == -1 && l[i-1] != '0') continue;
char o = l[i];
l[i] = l[i+k];
l[i+k] = o;
l = chuli(l);
string pp = ans[u];
pp = pp + char(y+48) + char(x+48) + char(k+48);
if(p[l] >= step + 1 || p[l] == 0) {//只有在步数更优的情况下才会更新ans
if(ans.count(l)) ans[l] = bj(pp,ans[l]);
else ans[l] = pp;
}
string aa = ans[l];
if(check(l)) {
oi = 1;
update_answer(l);
}
if(!vis[l] && _compare(l)) {
vis[l] = 1;
p[l] = p[u] + 1;
w.push(l);
}
}
}
}
}
int main() {
scanf("%d",&n);
string l;
for(int i = 0;i <= 4; i++)
for(int j = 0;j <= 20; j++) {
scanf("%d",&a[j][i]);
if(a[j][i] == 0) break;
}
for(int i = 0;i <= 6; i++) {
for(int j = 0;j <= 4; j++) {
char u = char(a[i][j] + 48);
l = l + u;
}
}
f_ans = "g";
p[l] = 1;
vis[l] = 1;
w.push(l);
bfs();
if(oi == 0) printf("-1");
else {
for(int i = 0;i < f_ans.length(); i++) {
if(f_ans[i] == '/')
cout << "-1";
else cout << f_ans[i] << ' ';
if(i % 3 == 2) cout << endl;
}
}
return 0;
}