洛谷 P1312 Mayan遊戲
阿新 • • 發佈:2020-10-22
題目傳送門
大模擬,用的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; }