标签:搜索
第一反应是搜索题,想了一下如果用BFS的话,由于状态过多,可能超内存,因此我用的DFS。
这里我们讨论一下剪枝条件:
如果当前状态有一种颜色的数量小于3,那么这种颜色就无法被消除,因此我们可以提前退出迭代。
如果两个连着的方块颜色是相同的话,我们不用交换。
如果两个非空的方块交换,我们只用考虑左边那个方块右移,而不用考虑右边方块左移的情况,这样就能做到右移优先。
如果一个方块是空的,它的右边非空,我们就只用考虑它右边的方块左移,当枚举到它右边方块的时候也不需要再考虑左移的情况。
注意下落清除方块的时候要写成循环形式,因为清除方块以后,下落形成的新图形可能又出现了能清除的方块。
下面是我第一次写的下落的程序,有一个BUG,如果上方多个方块连在一起,而最下面方块的下面是空的,根据我的最先写的程序,只有最下面的一个方块会往下掉,因此我们要一列一列的枚举,把目标状态先求出来
void drop() { for(int x = 0; x < 5; x++) for(int y = 6; y >= 1; y--) if(st[x][y] != 0&&st[x][y-1] == 0) swap(st[x][y],st[x][y-1]); return; }
void drop()//改进后的代码 { int num[10][10]; memset(num,-1,sizeof num); for(int x = 0; x < 5; x++)//这一步是按照合法的情况重新排版 { int h=0; for(int y = 0; y < 7; y++) if(st[x][y]) num[x][h++] = y; } for(int x = 0; x < 5; x++) for(int y = 0; y < 7; y++) st[x][y] = num[x][y] == -1?0:st[x][num[x][y]]; return; }
到了这里,这道题的思路就很简单了,就是写的时候有点坑爹
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> using namespace std; struct T { int x,y,ops; }ans[10]; int st[10][10]; int n; bool empty()//判断是否全部消除完 { for(int i = 0; i < 5; i++) for(int j = 0; j < 7; j++) if(st[i][j]) return false; return true; } void drop()//下移 { int num[10][10]; memset(num,-1,sizeof num); for(int x = 0; x < 5; x++)//这一步是按照合法的情况重新排版 { int h=0; for(int y = 0; y < 7; y++) if(st[x][y]) num[x][h++] = y; } for(int x = 0; x < 5; x++) for(int y = 0; y < 7; y++) st[x][y] = num[x][y] == -1?0:st[x][num[x][y]]; return; } bool clear()//清除合法的联通块,本题的难点 { bool flag = 0; for(int x = 0; x < 3; x++)//横向判断,因为至少3个相同的连在一起,因此x只用枚举到2 for(int y = 0; y < 7; y++) if(st[x][y])//有方块 { int x2; for(x2 = x; x2+1<5&&st[x2+1][y] == st[x][y]; x2++); if(x2 - x >= 2)//至少有3个连在一起 { int tx; for(tx = x; tx <= x2; tx++)//竖向判断是否有共用的情况 { int Up = y,Dn = y; while(Up+1<7&&st[tx][Up+1] == st[x][y]) Up++; while(Dn-1>=0&&st[tx][Dn-1] == st[x][y]) Dn--; if(Up - Dn >= 2) { int ty; for(ty = Dn; ty <= Up; ty++) st[tx][ty] = 0; } } for(tx = x; tx <= x2; tx++) st[tx][y] = 0; flag = 1; } } for(int x = 0; x < 5; x++) for(int y = 0; y < 5; y++) if(st[x][y]) { int y2; for(y2 = y; y2+1<7&&st[x][y2+1] == st[x][y]; y2++); if(y2 - y >= 2) { int ty; for(ty = y; ty <= y2; ty++) { int Lf = x,Ri = x; while(Lf-1>=0&&st[Lf-1][ty] == st[x][y]) Lf--; while(Ri+1<7&&st[Ri+1][ty] == st[x][y]) Ri++; if(Ri - Lf >= 2) { int tx; for(tx = Lf; tx <= Ri; tx++) st[tx][ty] = 0; } } for(ty = y; ty <= y2; ty++) st[x][ty] = 0; flag = 1; } } if(flag) return true; else return false; } void dfs(int step) { if(step > n) { if(empty()) { for(int i = 1; i <= n; i++) { if(ans[i].ops)//ops等于1是代表x右边那块往左移 printf("%d %d %d\n",ans[i].x+1,ans[i].y,-1); else printf("%d %d %d\n",ans[i].x,ans[i].y,1); } exit(0); } return; } int sum[12]; memset(sum,0,sizeof sum); for(int x = 0; x < 5; x++)//如果一个数它的个数已经小于3了,则不能被消除 for(int y = 0; y < 7; y++) sum[st[x][y]]++; for(int i = 1; i <= 10; i++) if(sum[i] != 0&&sum[i] < 3) return; for(int x = 0; x < 4; x++) for(int y = 0; y < 7; y++) if(st[x][y] != st[x+1][y])//颜色相同的就不用交换了 { ans[step].x = x; ans[step].y = y; ans[step].ops = (!st[x][y]);//如果当前这一块是空的话,那么我们就把它右边那一块左移,避免了分情况讨论 int temp[10][10]; memcpy(temp,st,sizeof temp); swap(st[x][y],st[x+1][y]); drop(); while(clear()) drop();//下移之后还肯能产生新的合法联通块,因此写成循环的形式 dfs(step+1);//迭代加深 ans[step].x = 0; ans[step].y = 0; ans[step].ops = 0; memcpy(st,temp,sizeof st); } } int main() { scanf("%d",&n); for(int i = 0; i < 5; i++) { for(int j = 0; ; j++) { scanf("%d",&st[i][j]); if(st[i][j] == 0) break; } } dfs(1); printf("-1\n"); return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:搜索
原文地址:http://blog.csdn.net/cqbzwja/article/details/47323343