poj 3279

很棒的一道题,既锻炼思维,又考验代码能力。在我温故知新结束之后是这样的一道题来迎接我,真的很棒。


思路:

    

    这本质上还是翻转问题,那么也就有一些理所当然的结论:

1、对每个棋子,只有翻转与不翻转的区别

2、翻转的顺序不会影响最终结果

不想证明,偷个懒233~,其实也是一目了然的事

不过和一般的翻转问题相比,它有点棘手,因为它既影响左右,又影响上下,如果只是一条线上的就是通常的翻转问题了,那么自然就想到想办法转换过去,那么,该如何做?

    假设当前需要判断第row(row > 1)行,row之前的行都已经操作过了, 那么该翻转哪个其实是固定的了,因为我要通过第row行的操作使上一行的1消失。无解的情况自然就是最后一行在复原了倒数第二行之后,它自己还有剩下的1。

    上面的分析其实就是对于每一个固定的第一行所需要进行的操作,那么再将第一行枚举一下不就涵盖了所有的情况了吗~

ok,结束

#include <iostream>
#include <cstring>
using namespace std;

const int inf = 0x3f3f3f3f;

int g[20][20], rem[20][20], ans[20][20], temp[20][20], vis[20];
int good;
int m, n;
int ccount = 1;
bool ok;

void dfs(int row, int cnt){
	for(int j = 1; j <= n; j ++){//更新状态 
		if(rem[row][j] == 1){
			g[row][j] = ! g[row][j];
			g[row][j - 1] = ! g[row][j - 1];
			g[row][j + 1] = ! g[row][j + 1];
			g[row - 1][j] = ! g[row - 1][j];
			g[row + 1][j] = ! g[row + 1][j];
		}
	}
	if(row == m){   //判断最后一行是否符合条件 
		bool flag = false;
		for(int i = 1; i <= n; i ++){
			if(g[row][i] == 1) //最后一行还存在1,则无解 
				flag = true ;
		}
		if(flag == false){
			ok = true;
			if(cnt < good){
				good = cnt;
				for(int i = 1; i <= m; i ++)
				for(int j = 1; j <= n; j ++)
					ans[i][j] = rem[i][j];
			}
			if(cnt == good){   //字典序 
				bool tag = true, flag1 = false;
				for(int i = 1; i <= m && tag; i ++)
				for(int j = 1; j <= n && tag; j ++){
					if(rem[i][j] < ans[i][j]){
						flag1 = true;
						tag = false;
					}
					if(rem[i][j] > ans[i][j]){
						tag = false;					
					}
				}
				if(flag1){
					for(int i = 1; i <= m; i ++)
					for(int j = 1; j <= n; j ++)
						ans[i][j] = rem[i][j];
				}
			}
		}
		return ;
	}
	for(int j = 1; j <= n; j ++){
		if(g[row][j] == 1){
			rem[row + 1][j] = 1;
			cnt ++;
		}
	}
	dfs(row + 1, cnt);
}

void f(int num, int cnt){
	if(num == n + 1){
		memset(rem, 0, sizeof(rem));
		for(int j = 1; j <= n; j ++)
			rem[1][j] = vis[j];
		dfs(1, cnt);
		for(int i = 1; i <= m; i ++)
		for(int j = 1; j <= n; j ++)
			g[i][j] = temp[i][j];
		return ;
	}
	vis[num] = 1;
	f(num + 1, cnt + 1);
	vis[num] = 0;
	f(num + 1, cnt);
}

int main(){
	cin >> m >> n;
	ok = false;
	good = inf;
	memset(temp, 0, sizeof(temp));
	memset(vis, 0, sizeof(vis));
	memset(g, 0, sizeof(g));
	for(int i = 1; i <= m; i ++)
	for(int j = 1; j <= n; j ++){
		cin >> temp[i][j];
		g[i][j] = temp[i][j];
	}
	f(1, 0);
	if(ok){
		for(int i = 1; i <= m; i ++){
			for(int j = 1; j < n; j ++){
				cout << ans[i][j] << ' ';
			}
			cout << ans[i][n] << endl;
		}
	}
	else{
		cout << "IMPOSSIBLE" << endl;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_38759433/article/details/80709229