题意:一个棋盘,0表示没放棋子,1 2 3 4表示放了该颜色的棋子,每次选择一个棋子消掉,同时跟它相连的同色棋子也会被消掉,消掉棋子后形成空格0,空格上方的棋子会掉下来,填补空格。如果某列全为0,右边整体向左移,填补空列。
分析:广搜 0ms
每行最多6个数,每个数为0~4,将其转化成一个6位数。 最多6行,所以一个状态需要6个数来保存,这里我用了一个长度为6的一维数组。。
每次从队列里取出一个状态,将其还原到二维数组里,取某棋子消掉,按要求填补空格得到新的二维数组,再将新数组进行压缩,入队列。
int dx[] = {-1,0,1,0};//up Right down Left int dy[] = {0,1,0,-1}; const int N = 6; int a[N][N+1], b[N][N], temp[N][N]; int n, m, cnt, ans; struct node{ int a[N], d; }u, v; queue<node> q; bool code(int *c){//将数组a[i][]编码成c[i] bool flag = true; FOR(i, 0, n) { c[i] = 0; FOR(j, 0, m) c[i] = c[i]*5+a[i][j]; if(c[i]) flag = false; } return flag; } void decode(int *c){//将c[i]中的数还原成数组a[i][] FOR(i, 0, n) FOD(j, m-1, 0){ a[i][j] = c[i]%5; c[i] /= 5; } } int t; void dfs(int x, int y){ FOR(i, 0, 4){ int xx=x+dx[i], yy=y+dy[i]; if(xx<0 || yy<0 || xx==n || yy==m) continue; if(a[xx][yy]==t && b[xx][yy]==0) { b[xx][yy]=cnt; dfs(xx, yy); } } } int tt[N]; void remove(int x, int y){ t = a[x][y]; b[x][y] = ++cnt; dfs(x, y);//深搜确定和a[x][y]相同且连通的部分 FOR(j, 0, m){//某列被去掉了一部分,剩余的下移 int p = 0; FOD(i, n-1, 0) { if(a[i][j] == 0) break; if(b[i][j]!=cnt) tt[p++] = a[i][j]; } FOR(i, 0, p) a[n-1-i][j] = tt[i]; FOR(i, 0, n-p) a[i][j] = 0; } FOR(j, 0, m) //某列都为0,右边的左移 if(a[n-1][j]==0) FOR(jj, j, m-1) FOR(i, 0, n) a[i][jj] = a[i][jj+1]; } void bfs(){ code(u.a); u.d=0; while(!q.empty()) q.pop(); q.push(u); while(!q.empty()){ u = q.front(); q.pop(); decode(u.a); FOR(i, 0, n) FOR(j, 0, m) b[i][j] = 0, temp[i][j] = a[i][j]; cnt = 0; FOR(j, 0, m){ FOD(i, n-1, 0){ if(a[i][j]==0) break; if(b[i][j] ) continue; remove(i, j); //把和ij相同的去掉 v.d = u.d+1; if( code(v.a) ) { ans = v.d; return;} q.push(v); FOR(ii, 0, n) FOR(jj, 0, m) a[ii][jj] = temp[ii][jj]; } } } } int main(){ #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); #endif while(~scanf("%d%d", &n, &m)){ FOR(i, 0, n) FOR(j, 0, m) scanf("%d", &a[i][j]); ans = 0; bfs(); printf("%d\n", ans); } return 0; }