题目大意:
一个冰箱有16个开关,只有16个开关同时处于打开状态,这个冰箱才可以打开。现给出4x4矩阵,表示16个开关状态,’+’表示开关关闭,’-‘表示开关打开。你可以改变任意一个位置为[i,j]开关的状态,但同时i行j列的所有开关状态同时改变。找出最少操作次数,并输出操作方案。本题操作方案有多种,输出任意一种均可。
题目来源:http://poj.org/problem?id=2965
输入示范:
-+--
----
----
-+--
输出示范:
6
1 1
1 3
1 4
4 1
4 3
4 4
解题思路:
算法:dfs + 位操作
这道题是一道枚举题目,与Poj1753有相似处。由于要输出路径,所以用dfs要比bfs方便。具体实现方法为:将输入的矩阵转换成01矩阵,表示开关状态,每次对[i, j]操作相当于对整行整列的所有数字进行对1的与非操作。为了方便,将4x4的01矩阵用int型变量前16位表示。对深度进行dfs找出最少的操作次数,并记录路径。代码如下。
//看了大神的代码,才知道,对dfs进行for循环也可以起到类似bfs的效果!看来看别人的代码也不全是坏事啊!!!
//不过呢,却没有bfs的效率,因为bfs的下一个状态是从上一个状态那里继承下来的,而对dfs进行从深度1到深度n的循环,每次重复操作都很多
#include<stdio.h>
int chess;
int ri[17], ci[17];
bool isopen(){
if(chess == 0)
return true;
else return false;
}
void flip(int bit){
int i, row = bit/4, col = bit%4;
chess ^= (1<<bit);
chess ^= (0xF<<(row*4));
for(i=0; i<4; i++)
chess ^= (1<<(i*4+col));
}
bool dfs(int bit, int deep, int step){
int row = bit/4, col = bit%4;
if(deep == step){
if(isopen())
return true;
else return false;
}
if(bit == 16)
return false;
ri[deep+1] = row; ci[deep+1] = col;
flip(bit);
if(dfs(bit+1, deep+1, step))
return true;
flip(bit);
return dfs(bit+1, deep, step);
}
int main(){
char a;
int i, j, step;
chess = 0;
for(i=0; i<4; i++){
for(j=0; j<4; j++){
a = getchar();
if(a == '+')
chess ^= (1<<i*4+j);
}
getchar();
}
for(i=1; i<=16; i++){
if(dfs(0, 0, i)){
step = i;
break;}
}
printf("%d\n",step);
for(i=1; i<=step; i++)
printf("%d %d\n", ri[i]+1, ci[i]+1);
return 0;
}