題目連接:https://www.luogu.org/problemnew/show/P1312html
個人第一篇題解!!函數
固然感謝ZAGER 的提示,他的連接https://www.cnblogs.com/ZAGER/p/9535526.htmlui
這道題是一個大暴搜,真實考驗了個人代碼能力……spa
寫函數是個好習慣,思路清晰明瞭。3d
分步驟code
定義map[i][j]表示當前地圖的狀況,last[x][i][j]表示第x步時地圖原貌,ans[x][i]記錄第x步時的操做htm
check()檢查是否被消完,固然根據規則只要檢查最下面一行是否都被消完便可;blog
bool check() { for(int i=1;i<=5;i++) { if(map[i][1]) return 0; } return 1; }
update()進行掉落過程,咱們從下往上搜,記錄當前map有值的時候其下面有幾個空行rem
void update()//掉落過程 { for(int i=1;i<=5;i++) { int down=0; for(int j=1;j<=7;j++) { if(!map[i][j]) down++; else { if(!down) continue; map[i][j-down]=map[i][j]; map[i][j]=0; } } } }
重點在這(對於我來講)get
轉換移動的操做,沒好好看題,移動的時候不必定只和其餘方塊互換,也能夠拖到懸空,而後掉落,因此互換後要檢查掉落狀況
void move(int x,int y,int z)//轉換移動 { int mem=map[x][y]; map[x][y]=map[x+z][y]; map[x+z][y]=mem; update(); while(remove()) update();//被消除後進行掉落 }
remove()用來進行消除過程。爲了知足條件圖5狀況,咱們先記錄在進行消除。
int remove()//消除過程 { bool flag=0; for(int i=1;i<=5;i++) { for(int j=1;j<=7;j++) { if(i>=2&&i<=4&&map[i][j]&&map[i][j]==map[i-1][j]&&map[i][j]==map[i+1][j]) { xx[i-1][j]=1;xx[i][j]=1;xx[i+1][j]=1;flag=1; } if(j>=2&&j<=6&&map[i][j]&&map[i][j]==map[i][j+1]&&map[i][j]==map[i][j-1]) { xx[i][j]=1;xx[i][j-1]=1;xx[i][j+1]=1;flag=1; } } }//先記錄再消除,知足圖五狀況 if(!flag) return 0; for(int i=1;i<=5;i++) { for(int j=1;j<=7;j++) { if(xx[i][j]) { map[i][j]=0; xx[i][j]=0; } } } return 1; }
還有幾個可有可無(也很重要)的小函數,代碼裏有註解
還有一個重要的剪枝,就是「向左的時候若是左方並不是是空,則跳過(不然能夠選擇其左側方塊右移,這樣字典序更小)」;
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n; int map[10][10],last[10][10][10],ans[10][5];//map當前地圖,;last第幾步移動前的地圖;ans是前爲步數,後爲答案 int xx[10][10]; bool check() { for(int i=1;i<=5;i++) { if(map[i][1]) return 0; } return 1; } void memory(int x) { for(int i=1;i<=5;i++) { for(int j=1;j<=7;j++) { last[x][i][j]=map[i][j];//記錄第x步時地圖的原貌 } } } void update()//掉落過程 { for(int i=1;i<=5;i++) { int down=0; for(int j=1;j<=7;j++) { if(!map[i][j]) down++; else { if(!down) continue; map[i][j-down]=map[i][j]; map[i][j]=0; } } } } int remove()//消除過程 { bool flag=0; for(int i=1;i<=5;i++) { for(int j=1;j<=7;j++) { if(i>=2&&i<=4&&map[i][j]&&map[i][j]==map[i-1][j]&&map[i][j]==map[i+1][j]) { xx[i-1][j]=1;xx[i][j]=1;xx[i+1][j]=1;flag=1; } if(j>=2&&j<=6&&map[i][j]&&map[i][j]==map[i][j+1]&&map[i][j]==map[i][j-1]) { xx[i][j]=1;xx[i][j-1]=1;xx[i][j+1]=1;flag=1; } } }//先記錄再消除,知足圖五狀況 if(!flag) return 0; for(int i=1;i<=5;i++) { for(int j=1;j<=7;j++) { if(xx[i][j]) { map[i][j]=0; xx[i][j]=0; } } } return 1; } void move(int x,int y,int z)//轉換移動 { int mem=map[x][y]; map[x][y]=map[x+z][y]; map[x+z][y]=mem; update(); while(remove()) update();//被消除後進行掉落 } void recover(int x) { for(int i=1;i<=5;i++) { for(int j=1;j<=7;j++) { map[i][j]=last[x][i][j]; } } ans[x][1]=0;ans[x][2]=0;ans[x][3]=0; } void dfs(int x) { if(check()) { for(int i=1;i<=n;i++) { if(i!=1) printf("\n"); for(int j=1;j<=3;j++) { printf("%d ",ans[i][j]); } } exit(0); } if(x==n+1) return ; memory(x); for(int i=1;i<=5;i++) { for(int j=1;j<=7;j++) { if(map[i][j]) { if(i<=6&&map[i][j]!=map[i+1][j]) { move(i,j,1); ans[x][1]=i-1;ans[x][2]=j-1;ans[x][3]=1; dfs(x+1); recover(x);//恢復原地圖和ans } } if(i>=2&&(!map[i-1][j])) { move(i,j,-1); ans[x][1]=i-1;ans[x][2]=j-1;ans[x][3]=-1; dfs(x+1); recover(x); } } } } int main() { scanf("%d",&n); for(int i=1;i<=5;i++) { for(int j=1;j<=8;j++) { int x; scanf("%d",&x); if(x==0) break; map[i][j]=x; } } dfs(1);//從第一步開始搜 printf("-1\n"); return 0; }