hdu3295 An interesting mobile game (IDA*)

题意:一个6*6的矩阵,最多有4种颜色的棋子,相邻两个或两个以上相同颜色的棋子可以消掉。

如果棋子下方有空,棋子会向下掉。

如果一整列都被消完,右边的棋子会整体向左移。


做法:ID+深搜。只不过每次从联通个数最多的棋子开始消。但是这样写完只有140ms。还有一个重要的优化:

之前的代码是

bool dfs(int step) {
	if (ended() && step == depth) return true;
	if (step > depth) return false;
	//---------
}

当当前的step大于搜索的深度时return,但这样做还不够。

假设现在棋盘上还有n种颜色的棋子,那么最理想状态下还需要消n次。所以如果step + n > depth,那么无论如何都无法消完,直接return false。在floolfill时顺便统计颜色个数就行了。

加上这个优化0ms。


完整代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>

using namespace std;

struct Block{
	int x, y, cnt;
	Block(int a, int b, int c) : x(a), y(b), cnt(c) {}
	bool operator < (const Block & b) const {
		return cnt > b.cnt;
	}
};

struct Point{
	int x, y;
	Point(int a, int b) : x(a), y(b) {}
};

int n, m;
int dir[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
int arr[8][8];
int g[8][8];
int depth;
int vis[8][8];

bool ended() {
	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
			if (g[i][j]) return false;
	return true;
}

int floodFill(int x, int y, int color) {
	int ans = 1;
	vis[x][y] = 1;
	for (int i = 0; i < 4; i++) {
		int nx = x + dir[i][0];
		int ny = y + dir[i][1];
		if (nx >= 0 && nx < n && ny >= 0 && ny < m && g[nx][ny] == color && !vis[nx][ny]) {
			ans += floodFill(nx, ny, color);
		}
	}
	return ans;
}

void change() {
	int emp[8] = {0}, t;
	for (int j = 0; j < m; j++) {
		for (int i = n - 1; i >= 0; i--) {
			if (g[i][j]) continue;
			int t = i;
			while (!g[t][j]) t--;
			if (t >= 0) {
				g[i][j] = g[t][j];
				g[t][j] = 0;
			}
		}
		for (t = n - 1; t >= 0; t--)
			if (g[t][j]) break;
		if (t < 0) emp[j] = 1;
	}
	for (int j = 0, flag = 0; j < m - flag; j++) {
		if (!emp[j]) continue;
		for (int i = n - 1; i >= 0; i--) {
			for (int k = j - flag + 1; k < m - flag; k++) {
				g[i][k - 1] = g[i][k];
			}
			g[i][m - flag - 1] = 0;
		}
		flag++;
	}
}

void remv(int sx, int sy) {
	queue<Point> q;
	int done[8][8];
	memset(done, 0, sizeof(done));
	Point p = Point(sx, sy);
	q.push(p);
	int color = g[sx][sy];
	g[sx][sy] = 0;
	while (!q.empty()) {
		p = q.front();
		q.pop();
		for (int i = 0; i < 4; i++) {
			int nx = p.x + dir[i][0];
			int ny = p.y + dir[i][1];
			if (nx >= 0 && nx < n && ny >= 0 && ny < m && g[nx][ny] == color) {
				g[nx][ny] = 0;
				q.push(Point(nx, ny));
			}
		}
	}
}

bool dfs(int step) {
	if (ended() && step == depth) return true;
	if (step > depth) return false;
	int map[8][8];
	memcpy(map, g, sizeof(g));
	memset(vis, 0, sizeof(vis));
	vector<Block> blocks;
	int color = 0;
	int done[5] = {0};
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			if (!map[i][j] || vis[i][j]) continue;
			int num = floodFill(i, j, map[i][j]);
			blocks.push_back(Block(i, j, num));
			if (!done[map[i][j]]) {
				color++;
				done[map[i][j]] = 1;
			}
		}
	}
	if (color + step > depth) return false;
	sort(blocks.begin(), blocks.end());
	for (int i = 0; i < blocks.size(); i++) {
		memcpy(g, map, sizeof(map));
		remv(blocks[i].x, blocks[i].y);
		change();
		if (dfs(step + 1)) return true;
	}
	return false;
}

int main() {
	while (~scanf("%d %d", &n, &m)) {
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				scanf("%d", &arr[i][j]);
			}
		}
		for (depth = 0; depth < 2222; depth++) {
			memcpy(g, arr, sizeof(arr));
			if (dfs(0)) {
				printf("%d\n", depth);
				break;
			}
		}
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值