[luogu P1312]Mayan遊戲
阿新 • • 發佈:2020-12-22
其實就是一道鍛鍊碼力的簡單題……
看到題目中的\(0<x\leqslant 5\)也就知道是爆搜了吧(
我們仿照寫遊戲的方法多寫幾個函式,能夠有效降低錯誤率(確信
我們寫出大致的搜尋流程來:
如果當前步數大於\(n\)直接返回;
如果當前已經為終態,直接輸出答案;
否則列舉每種可能情況繼續搜。
沒錯就是這麼暴力
接下來講具體實現。
首先我們對全域性變數和陣列進行一下約定:
int n;//見題目 int board[10][10];//棋盤 int step[10][10];//儲存步數 int mem[10][10][10];//鑑於搜尋下一步的時候我們會不可避免地更改原陣列,我們需要儲存一下當前的狀態 bool del[10][10];//見remove函式部分
一開始的讀入非常簡單:讀到0換行即可
scanf("%d",&n);
for(int i=1;i<=5;i++)
{
int cnt=0;
while(1)
{
int xx;scanf("%d",&xx);
if(xx==0)break;
board[i][++cnt]=xx;
}
}
我們需要對題目的一些操作進行一下模擬。
首先是fall函式:它讓懸空的塊下落。
可以發現,我們用一個變數來存下移的最終位置,就可以簡單地進行實現。
void fall() { int cnt; for(int i=1;i<=5;i++) { cnt=0; for(int j=1;j<=7;j++) { if(board[i][j]==0)cnt++; else { if(cnt==0)continue; board[i][j-cnt]=board[i][j]; board[i][j]=0; } } } }
然後是三消remove函式:
我們分別暴力判斷橫向和縱向每一次可以消掉哪些塊,全都用del陣列給標記出來,最後一起消掉。
別忘了最後要將del陣列清零,消完之後fall一次讓可能懸空的塊下墜。
當然就像樣例一樣,一次消除是:消除當前->下墜->出現新的可三消塊->再次消除當前……
於是我們將這個函式修改一下,讓它發現本次有消除操作就返回1,沒有就返回0。
於是我們可以這樣呼叫remove函式:
while(remove());
簡單粗暴(
remove函式實現:
bool remove() { bool flag=0; for(int i=1;i<=5;i++) for(int j=2;j<=6;j++) if(board[i][j]!=0&&board[i][j]==board[i][j-1]&&board[i][j]==board[i][j+1]) { flag=1; del[i][j]=del[i][j-1]=del[i][j+1]=1; } for(int i=2;i<=4;i++) for(int j=1;j<=7;j++) if(board[i][j]!=0&&board[i][j]==board[i-1][j]&&board[i][j]==board[i+1][j]) { flag=1; del[i][j]=del[i-1][j]=del[i+1][j]=1; } if(!flag)return 0; for(int i=1;i<=5;i++) for(int j=1;j<=7;j++) if(del[i][j]) board[i][j]=del[i][j]=0; fall(); return 1; }
接下來是移動塊函式move和判斷是否結束函式gameover。
move函式只需要移動一次並呼叫fall墜落一次,然後remove即可。
gameover直接全屏掃。
void move(int xx,int yy,int dir)//用dir標記方向
{
swap(board[xx][yy],board[xx+dir][yy]);
fall();while(remove());
}
bool gameover()
{
for(int i=1;i<=5;i++)
if(board[i][1]!=0)
return 0;
return 1;
}
接下來是dfs函式的列舉部分。
首先我們用mem儲存一下;
然後只需要分方向列舉,列舉到一種情況就記錄步數繼續搜;
回溯的時候撤銷所記錄的步數,用mem陣列換回原來的狀態即可。
一個小剪枝:在交換之前判斷一下,避免將相同的塊交換即可。
for(int i=1;i<=5;i++)
for(int j=1;j<=7;j++)
mem[xx][i][j]=board[i][j];
for(int i=1;i<=5;i++)
for(int j=1;j<=7;j++)
if(board[i][j]!=0)
{
if(i<=4&&board[i][j]!=board[i+1][j])
{
move(i,j,1);
step[xx][1]=i-1;step[xx][2]=j-1;step[xx][3]=1;
dfs(xx+1);
step[xx][1]=step[xx][2]=step[xx][3]=-1;
for(int i=1;i<=5;i++)
for(int j=1;j<=7;j++)
board[i][j]=mem[xx][i][j];
}
if(i>=2&&board[i][j]!=board[i-1][j])
{
move(i,j,-1);
step[xx][1]=i-1;step[xx][2]=j-1;step[xx][3]=-1;
dfs(xx+1);
step[xx][1]=step[xx][2]=step[xx][3]=-1;
for(int i=1;i<=5;i++)
for(int j=1;j<=7;j++)
board[i][j]=mem[xx][i][j];
}
}
於是我們就這麼水完了一道藍題
完整程式碼:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
int n,board[10][10],step[10][10],mem[10][10][10];
bool del[10][10];
void fall()
{
int cnt;
for(int i=1;i<=5;i++)
{
cnt=0;
for(int j=1;j<=7;j++)
{
if(board[i][j]==0)cnt++;
else
{
if(cnt==0)continue;
board[i][j-cnt]=board[i][j];
board[i][j]=0;
}
}
}
}
bool remove()
{
bool flag=0;
for(int i=1;i<=5;i++)
for(int j=2;j<=6;j++)
if(board[i][j]!=0&&board[i][j]==board[i][j-1]&&board[i][j]==board[i][j+1])
{
flag=1;
del[i][j]=del[i][j-1]=del[i][j+1]=1;
}
for(int i=2;i<=4;i++)
for(int j=1;j<=7;j++)
if(board[i][j]!=0&&board[i][j]==board[i-1][j]&&board[i][j]==board[i+1][j])
{
flag=1;
del[i][j]=del[i-1][j]=del[i+1][j]=1;
}
if(!flag)return 0;
for(int i=1;i<=5;i++)
for(int j=1;j<=7;j++)
if(del[i][j])
board[i][j]=del[i][j]=0;
fall();
return 1;
}
void move(int xx,int yy,int dir)
{
swap(board[xx][yy],board[xx+dir][yy]);
fall();while(remove());
}
bool gameover()
{
for(int i=1;i<=5;i++)
if(board[i][1]!=0)
return 0;
return 1;
}
void dfs(int xx)
{
if(gameover())
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=3;j++)printf("%d ",step[i][j]);
printf("\n");
}
exit(0);
}
if(xx>n)return;
for(int i=1;i<=5;i++)
for(int j=1;j<=7;j++)
mem[xx][i][j]=board[i][j];
for(int i=1;i<=5;i++)
for(int j=1;j<=7;j++)
if(board[i][j]!=0)
{
if(i<=4&&board[i][j]!=board[i+1][j])
{
move(i,j,1);
step[xx][1]=i-1;step[xx][2]=j-1;step[xx][3]=1;
dfs(xx+1);
step[xx][1]=step[xx][2]=step[xx][3]=-1;
for(int i=1;i<=5;i++)
for(int j=1;j<=7;j++)
board[i][j]=mem[xx][i][j];
}
if(i>=2&&board[i][j]!=board[i-1][j])
{
move(i,j,-1);
step[xx][1]=i-1;step[xx][2]=j-1;step[xx][3]=-1;
dfs(xx+1);
step[xx][1]=step[xx][2]=step[xx][3]=-1;
for(int i=1;i<=5;i++)
for(int j=1;j<=7;j++)
board[i][j]=mem[xx][i][j];
}
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=5;i++)
{
int cnt=0;
while(1)
{
int xx;scanf("%d",&xx);
if(xx==0)break;
board[i][++cnt]=xx;
}
}
dfs(1);
printf("-1\n");
return 0;
}
最慢的點跑了1.09s,但還是夠AC了(笑