POJ-3279 经典翻转问题

题目大意:给定一个矩阵,要么黑要么白,求出按照规则将其翻转为全白最小翻转次数的方案,如有多种最小方案则输出字典序最小的方案

分析:此题为经典的翻转问题(开关问题),在看此题解析之前,希望大家看看我这篇文章:点击打开链接

附上代码:

#include<cstdio>
#include<cstring>
using namespace std;
#define INF 0x3f3f3f3f
bool a[20][20];   //存图
bool b[20][20];   //保存当前翻转方案
bool c[20][20];   //保存最优解
int d[5][2] = { { -1, 0 }, { 1, 0 }, { 0, 0 }, { 0, -1 }, { 0, 1 } };
int ans = INF;
int n, m;
bool getcolor(int x, int y)    //得到x,y的颜色
{
	int res = a[x][y];
	for (int i = 0; i < 5; i++)
	{
		int fx = x + d[i][0], fy = y + d[i][1];
		if (fx >= 1 && fx <= n && fy >= 1 && fy <= m) res += b[fx][fy];
	}
	return res % 2;
}
int solve()
{
	int res = 0;
	for (int i = 2; i <= n; i++)    //从第二行开始检查是否需要翻转
		for (int j = 1; j <= m; j++)
			if (getcolor(i - 1, j)) b[i][j] = 1;
	for (int i = 1; i <= m; i++)     //检查最后一行是否全为白色
		if (getcolor(n, i)) return INF;
	for (int i = 1; i <= n; i++)    //统计翻转次数 
		for (int j = 1; j <= m; j++)
			res += b[i][j];
	return res;
}
int main()
{
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			scanf("%d", &a[i][j]);
	for (int s = 0; s < 1 << m; s++)   //按照字典序枚举第一行所以翻转可能
	{
		memset(b, false, sizeof b);
		for (int i = 1; i <= m; i++)
			b[1][i] = s >> (m - i) & 1;
		int t = solve();
		if (t < ans)
		{
			ans = t;
			memcpy(c, b, sizeof b);
		}
	}
	if (ans == INF) printf("IMPOSSIBLE\n");
	else 
	{
		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= m; j++)
				printf("%d ", c[i][j]);
			printf("\n");
		}
	}
	return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值