您的位置:首页 > 其它

POJ-3279 经典翻转问题

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

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

附上代码:

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: