kuangbing题单(1)简单搜索POJ 3279 Fliptile

先附上题目链接
一道搜索题,但有转弯的地方.
如果考虑搜索全局的话,在题目给的最大规模情况下时间是不可承受的(2的225次方).所以应进行分析.
因为在每一行进行翻转之后.它的最终状态只取决于它的下一行翻转的情况.比如第一行在进行翻转之后的状态是1 0 0 1.那么要使最后全部变为0,第二行就必须翻转第一个格子和第四个格子,如此只要这样进行下去.判断全部翻转完毕后最后一行是否是全为0即可.
如此一来只需要枚举第一行的翻转情况.这一步的代价是2^n(本人是习惯把行数看成n列数看成m,但题目是反过来的,不过没有影响.).之后所进行的步骤只是扫描一遍图,代价是(n-1)*m的.这样复杂度从2的m×n次方下降到了2的n次方×n×m.勉强符合了题目的要求.
代码的细节方面,在第一行枚举结束后.应该将当前的瓷砖图和翻转图记录下来再操作(WA了几发都是忘记记录翻转图).而且在得到更小的翻转数时要更新最后的答案图和最小翻转数.因为题目是要求字典序最小.而我是顺序枚举的.判断的条件应该是小于时更新答案.如果是逆序的话就应该在小于等于时更新答案(这个方法在紫书上lrj解释过).无解的情况我是通过一个布尔型全局变量初始化为false如果得到一个解就将它赋值为true.最后判断这个变量是否为真就可以判断有无解了.
附上代码.

#include <iostream>
#include <queue>
#include <string.h>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
typedef long long ll;
const int mn = 20;
int n, m;
bool maze[mn][mn];
bool ans[mn][mn];
bool tans[mn][mn];
bool finalans[mn][mn];
int minans = INF;
bool tmaze[mn][mn];
bool allflag;
bool inside(int r, int c) {
	if (r >= 0 && r < n && c >= 0 && c < m) return true;
	return false;
}
void flipcube(int r, int c) {
	maze[r][c] = !maze[r][c];
	if (inside(r + 1, c))maze[r + 1][c] = !maze[r + 1][c];
	if (inside(r, c + 1))maze[r][c + 1] = !maze[r][c + 1];
	if (inside(r - 1, c))maze[r - 1][c] = !maze[r - 1][c];
	if (inside(r, c - 1))maze[r][c - 1] = !maze[r][c - 1];
}
void dfs(int i) {
	if (i == m) {
		for (int j = 0; j < n; ++j) {
			for (int k = 0; k < m; ++k) {
				tmaze[j][k] = maze[j][k];
			}
		}
		for (int j = 0; j < n; ++j) {
			for (int k = 0; k < m; ++k) {
				tans[j][k] = ans[j][k];
			}
		}
		int cnt = 0;
		for (int j = 1; j < n; ++j) {
			for (int k = 0; k < m; ++k) {
				if (tmaze[j - 1][k]) {
					tans[j][k] = 1;
					cnt++;
					tmaze[j][k] = !tmaze[j][k];
					if (inside(j + 1, k))tmaze[j + 1][k] = !tmaze[j + 1][k];
					if (inside(j, k + 1))tmaze[j][k + 1] = !tmaze[j][k + 1];
					if (inside(j - 1, k))tmaze[j - 1][k] = !tmaze[j - 1][k];
					if (inside(j, k - 1))tmaze[j][k - 1] = !tmaze[j][k - 1];
				}
			}
		}
		bool flag = 1;
		for (int j = 0; j < m; ++j) {
			if (tmaze[n - 1][j]) flag = 0;
		}
		if (flag) {
			allflag = 1;
			for (int j = 0; j < m; ++j) {
				if (tans[0][j]) cnt++;
			}
			if (cnt < minans) {
				minans = cnt;
				for (int j = 0; j < n; ++j) {
					for (int k = 0; k < m; ++k)
						finalans[j][k] = tans[j][k];
				}
			}
		}
		return;
	}
	dfs(i + 1);
	ans[0][i] = 1;
	flipcube(0, i);
	dfs(i + 1);
	ans[0][i] = 0;
	flipcube(0, i);
}
int main() {
	cin >> n >> m;
	for (int i = 0; i < n; ++i) {
		for (int j = 0; j < m; ++j) {
			cin >> maze[i][j];
		}
	}
	dfs(0);
	if (!allflag) {
		cout << "IMPOSSIBLE";
		return 0;
	}
	for (int i = 0; i < n; ++i) {
		cout << finalans[i][0];
		for (int j = 1; j < m; ++j) {
			cout << " " << finalans[i][j];
		}
		cout << endl;
	}

	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值