$Mayan$遊戲
\(Mayan\)遊戲
好啊,一年(半年)來的夢魘,終於結束了。
其實我從來沒料到整體竟然會如此暴力……做的時候機房裡冷得很,感覺暈暈乎乎地做完了,暈暈乎乎地調了好久,暈暈乎乎地聽(看了題解的)\(qcr\)給我講怎麼優化程式碼量,怎麼剪枝。
每次搜尋要保留本次的狀態,這是比較好想的,我也成功的想到了。但是問題是我們不能單純地用一個二維陣列來\(copy\),需要記錄步數,不然就會錯誤\(copy\_back\)。於是最終我們需要一個三維陣列來記錄。後半段是\(qcr\)告訴我的。
大概就是……我從來沒想到\(Mayan\)遊戲,會讓你每一層\(dfs\)真正地搜全部\(5 \times 7=35\)
還有就是一個小小的剪枝兒。就是由於對於每一個格子,我們考慮它向兩邊替換,而我們為了避免重複搜尋,所以就決定單向搜尋,即對於每個塊,如果他左邊也是一個塊,那就不去\(exchange\),只考慮右邊;而如果左邊是空白格,才\(exchange\)。顯然這個剪枝兒的優化性是很顯著的。
我一開始寫的\(remove()\)、\(down()\)和\(check()\)十分的麻煩——或者說專一?反正之後我懶得除錯了,直接聽的\(qcr\)的,每次執行這幾個函式的時候,直接全屏掃一遍。
\(qcr\)給我講了一個很神的\(down()\)函式。
對於\(exchange\),我們要不斷的\(while(remove()) ~;\)
最後我掛了……幾個點來著……忘記了。反正原因是因為,每次\(remove()\)之前應該先\(down()\),然而我並沒有\(down()\)乾淨233
最後再說一個剪枝兒,不是必要性的,但是確實可以加快速度。就是我們再每次遍歷\(7 \times 5\)的時候,遇到空白的,不是
continue
而是break
,因為我們\(down\)一定是完備的,所以可以少好幾次空遍歷。- 這是個好題,怎麼說呢,折射我程式碼能力弱的好題。
- 程式碼大概\(5k+\)左右
向我自己致敬
// luogu-judger-enable-o2 #include <stack> #include <cstdio> #include <cstring> #include <iostream> using namespace std ; struct D{ int x, y ;} ; stack <D> s ; struct Ans{ int x, y, d ;} res[100] ; int Remove[50][50] ; int N, T[30][30], base[4000][10][10], qwq[4000][30], color[30], i, j, t, tot ; inline int qr(){ int res = 0 ; char c = getchar() ; while (!isdigit(c)) c = getchar() ; while (isdigit(c)) res = (res << 1) + (res << 3) + c - 48, c = getchar() ; return res ; } /*inline void clear(){ while (!s.empty()) s.pop() ; }*/ /*inline void remove(){ for (int di = 1 ; di <= 5 ; ++ di) for (int dj = 1 ; dj <= 7 ; ++ dj) if (T[di][dj] != -1 int cnt = 0 ; for (int ki = di + 1 ; ki <= 5 && T[ki][dj] == T[di][dj] ; ++ ki) ++ cnt, s.push((D){ki, dj}) ; for (int ki = di - 1 ; ki >= 1 && T[ki][dj] == T[di][dj] ; -- ki) ++ cnt, s.push((D){ki, dj}) ; for (int ki = dj + 1 ; ki <= 7 && T[di][ki] == T[di][dj] ; ++ ki) ++ cnt, s.push((D){di, ki}) ; for (int ki = dj - 1 ; ki >= 1 && T[di][ki] == T[di][dj] ; -- ki) ++ cnt, s.push((D){di, ki}) ; if (cnt + 1 >= 3){ color[T[di][dj]] -= cnt + 1 ; while (!s.empty()) T[s.top().x][s.top().y] = -1, s.pop() ; for (int ki = 1 ; ki <= 5 ; ++ ki) if (T[ki][dj] == -1){ for (int k = dj ; k <= 7 && (T[ki][k] != -1 || k == dj) ; ++ k) T[ki][k] = T[ki][k + 1] ; T[ki][0] -- ; } } else clear() ; } }*/ /*inline void down(){ for (int di = 1 ; di <= 5 ; ++ di){ int ttt = 0 ; for (int dj = 1 ; dj <= 7 ; ++ dj) if (T[di][dj] == -1){ ++ ttt ; for (int k = dj ; k <= 7 ; ++ k) T[di][k] = T[di][k + 1] ; } T[di][0] = 7 - ttt ; } }*/ inline void down(){//妙啊 int ttt = 0 ; for(int di = 1 ; di <= 5 ; ++ di){ ttt = 0 ; for(int dj = 1 ; dj <= 7 ; ++ dj) if(T[di][dj] == -1) ++ ttt ; else{ if(! ttt) continue ; T[di][dj - ttt] = T[di][dj], T[di][dj] = -1 ; } // T[di][0] = 7 - ttt ; } } inline bool remove(){ // void -> bool bool Mark = 0 ; memset(Remove, 0, sizeof(Remove)) ; for (int di = 1 ; di <= 5 ; ++ di) for (int dj = 1 ; dj <= 7 ; ++ dj){ if (T[di][dj] != -1 && di >= 2 && di <= 4 && T[di][dj] == T[di + 1][dj] && T[di][dj] == T[di - 1][dj]){ Remove[di + 1][dj] = Remove[di - 1][dj] = Remove[di][dj] = 1, Mark = 1 ; } if (T[di][dj] != -1 && dj >= 2 && dj <= 6 && T[di][dj] == T[di][dj + 1] && T[di][dj] == T[di][dj - 1]){ Remove[di][dj + 1] = Remove[di][dj - 1] = Remove[di][dj] = 1, Mark = 1 ; } } if (!Mark) return 0 ; for (int di = 1 ; di <= 5 ; ++ di) for (int dj = 1 ; dj <= 7 ; ++ dj) T[di][dj] = (!Remove[di][dj]) ? T[di][dj] : -1 ; down() ; return 1 ; } /* inline void down(int x, int y, int d){ if (d == 1){ int k, temp = T[x][y] ; for (k = y ; k <= 7 && T[x][k] != -1 ; ++ k) T[x][k] = T[x][k + 1] ; for (k = y ; k >= 1 && T[x - 1][k - 1] == -1 ; -- k) ; T[x - 1][k] = temp ; T[x][0] --, T[x - 1][0] ++ ; } else { int k, temp = T[x][y] ; for (k = y ; k <= 7 && T[x][k] != -1 ; ++ k) T[x][k] = T[x][k + 1] ; for (k = y ; k >= 1 && T[x + 1][k - 1] == -1 ; -- k) ; T[x + 1][k] = temp ; T[x][0] --, T[x + 1][0] ++ ; } remove() ; return ; }*/ inline bool judge(){ for (int di = 1 ; di <= 5 ; ++ di) for (int dj = 1 ; dj <= 7 ; ++ dj) if (T[di][dj] != -1) return false ; return true ; } inline void _reset(int x){ for (int di = 1 ; di <= 5 ; ++ di) for (int dj = 1 ; dj <= 7 ; ++ dj) T[di][dj] = base[x][di][dj] ; } inline void Prepare(int x){ for (int di = 1 ; di <= 5 ; ++ di) for (int dj = 1 ; dj <= 7 ; ++ dj) base[x][di][dj] = T[di][dj] ; } inline void dfs_work(int step){ if (judge()){ for (int di = 1 ; di <= N ; ++ di) printf("%d %d %d\n", res[di].x, res[di].y, res[di].d) ; exit(0) ; } /*for (int di = 1 ; di <=5 ; ++ di) for (int dj = 1 ; dj <= 7 ; ++ dj) printf("%d%c", T[di][dj], " \n"[dj == 7]) ; */ if (step == N + 1) return ; Prepare(step) ; for (int di = 1 ; di <= 5 ; ++ di) for (int dj = 1 ; dj <= 7 ; ++ dj){ if (T[di][dj] == -1) break ; if (di > 1 && T[di - 1][dj] == -1){ swap(T[di][dj], T[di - 1][dj]) ; down() ; while (remove()) ;//after exchange, need down res[step] = (Ans){di - 1, dj - 1, -1} ; dfs_work(step + 1) ; _reset(step) ; res[step] = (Ans){-1, -1, -1} ; } if (di < 5 && T[di][dj] != T[di + 1][dj]){ swap(T[di][dj], T[di + 1][dj]) ; down() ; while(remove()) ; res[step] = (Ans){di - 1, dj - 1 ,1} ; dfs_work(step + 1) ; _reset(step) ; res[step] = (Ans){-1, -1, -1} ; } } } //problem1 : no reset -> correct //problem1.5 : the same state -> ? //problem2 : It's not a good way to search //ERROR : Why is it broken? How to solve it? int main(){ // freopen("std.out", "w", stdout) ; cin >> N ; memset(T, -1, sizeof(T)) ; for (i = 1 ; i <= 5 ; ++ i) T[i][0] = 0 ; for (i = 1 ; i <= 5 ; ++ i) while((t = qr()) != 0) T[i][++ T[i][0]] = t ; dfs_work(1) ; cout << -1 << endl ; return 0 ; }