【题目链接】
http://poj.org/problem?id=3279
题目意思
给一个n*m的矩阵,1代表黑色方块,0代表白色方块。现在一只牛要把全部方块翻成白色,它一脚下去能把白变黑,黑变白。由于蹄子太大当它踩某格时候周围上下左右都将根随变换。问牛最少踩的次数的方案,如果有多种输出字典序小的。无法则输出 “IMPOSSIBLE”
解题思路
因为白的踩一变黑的,黑的踩一次变白的,所以每个格子最多踩一次就可以了,多踩又变回去了。当第n行确定,为了保证第n行的1都变成0,第n+1行踩的位子只能是上行为1的位子。所以当第1行确定了整个图踩的方案就确定了。只要判断最后一行踩完后是否全为0,是则方案可行否则不可以行。枚举第一行全部的踩法找最优。
可以开二维数组记图,也可以用二进制来表示。(n不大)具体看代码吧
代码部分
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;
#define LL long long
#define inf 0x3f3f3f3
const int N = 1e5+5;
int mp[16];
int a[16]; //记录踩完后的图
int b[16]; //记录最小方案
int c[16]; //记录每层踩的位子
int mn;
int n,m;
void dfs(int i,int k,int ans) //行数;第i-1行的值,同样数第i行需要踩的格子;步数
{
c[i] = k;
if (i == n){
if (!k && mn > ans){
mn = ans;
for (int i = 0; i < n; i++)
b[i] = c[i];
}
return;
}
a[i] ^= mp[i]; //拿两个变量来记录本行和下一行也可以
int s = 0;
for (int j = 1; j <= k;j <<= 1){
if (j&k){
s++;
a[i] ^= j; //本身
if (j < (1<<(m-1))) //右
a[i] ^= (j<<1);
if (j != 1) //左
a[i] ^= (j>>1);
a[i+1] ^= j; 下
}
}
dfs(i+1,a[i],ans+s);
}
int main()
{
while (~scanf("%d %d",&n,&m))
{
mn = inf;
memset(mp,0,sizeof(mp));
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++){
int t;
scanf("%d",&t);
mp[i] |= t<<j;
}
for (int i = 0; i < (1<<m); i++){
memset(a,0,sizeof(a));
dfs(0,i,0);
}
if (mn == inf)
printf("IMPOSSIBLE\n");
else
for (int i =0; i < n; i++){
int k = b[i];
for (int i = 0; i < m; i++){
if (k&1)
printf("1");
else printf("0");
k >>= 1;
printf("%c",i != m-1? ' ':'\n');
}
}
}
return 0;
}
/*
4 4
1 0 0 1
0 1 1 0
0 1 1 0
1 0 0 1
1 4
0 1 1 1
2 4
0 0 1 1
0 0 1 1
*/