//题意:同样给你一个4*4的矩阵,但每一个点代表一个开关,开关可开可闭,只有开关全部打开时才有用,你每一次打开或者关闭一个开关会导致与他相同的行的开关以及与他同列的开关反转,问最少多少次可全部打开并且打印顺序,若有多解则任意输出一组反转顺序即可
//思路:和poj1753思路基本一致,不同的地方:1)在这里的中之状态只有一个,全开,而1753有两个全开或者全闭 ;2)此题要求输出这个非常容易,只要判断出是哪一种情况切实最小值时,保存最后简单循环处理输出即可;3)此题的坑在于每次反转重复次数过多,如果每次手动用函数反转必定超时按照1753的思路的话,因此直接打表将16种反转情况达标即可;【注意】:若不懂可先将poj1753弄懂两个题完全一样思路点击打开博主的poj1753。(博主的poj1753 flip函数就是手动反转的过程,此题若手动函数反转会超时,则将所有反转的值直接保存在数组t中即可)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int const len = 16;
char branch[4][4];
int t[16]={63624,62532,61986,61713,36744,20292,12066,7953,35064,17652,8946,4593,34959,17487,8751,4383};
//二进制下标
/*
15 14 13 12
11 10 9 8
7 6 5 4
3 2 1 0
*/
/*
-+--
----
----
-+--
*/
int main()
{
while(scanf("%s", branch) != EOF){
int status = 0; //全+为0 全1为#ffff
int num = len;
int print;
int cnt = 20;
for(int i = 1; i < 4; i++){
getchar();
scanf("%s", branch[i]);
}
for(int i = 0; i < 4; i++){
for(int j = 0; j < 4; j++){
num--;
if(branch[i][j] == '-')
status ^= 1 << num;
}
}
for(int i = 0; i <= 0xffff; i++){
int status_ = status; //副本
int step = 0;
int index = 15;
for(int j = 0; j <= 15; j++){
if((1<<j) & i){
status_ ^= t[index];
step++;
}
if(status_ == 0xffff && step <= 16){
if(step < cnt){
cnt = step;
print = i;
}
}
index--;
}
}
printf("%d\n", cnt);
for(int i = 15; i >= 0; i--){
if((1 << i) & print){
printf("%d %d\n", 5-(i/4 + 1), 5-(i%4 + 1));//这里需要将输出的下表更改,因为我的二进制下表见上面注释
}
}
}
return 0;
}