当前位置: 代码迷 >> 综合 >> [POJ] 2965.The Pilots Brothers' refrigerator
  详细解决方案

[POJ] 2965.The Pilots Brothers' refrigerator

热度:21   发布时间:2024-01-05 01:16:57.0

The Pilots Brothers’ refrigerator

Time Limit: 1000MS      Memory Limit: 65536K
Total Submissions: 29786        Accepted: 11550     Special Judge

Description

The game “The Pilots Brothers: following the stripy elephant” has a quest where a player needs to 
open a refrigerator.
There are 16 handles on the refrigerator door. Every handle can be in one of two states: open or 
matrix 4х4. You can change the state of a handle in any location [i, j] (1 ≤ i, j ≤ 4). However, 
this also changes states of all handles in row i and all handles in column j.
The task is to determine the minimum number of handle switching necessary to open the refrigerator.

Input

The input contains four lines. Each of the four lines contains four characters describing the 
initial state of appropriate handles. A symbol “+” means that the handle is in closed state, whereas 
the symbol “?” means “open”. At least one of the handles is initially closed.

Output

The first line of the input contains N – the minimum number of switching. The rest N lines describe 
switching sequence. Each of the lines contains a row number and a column number of the matrix 
separated by one or more spaces. If there are several solutions, you may give any one of them.

Sample Input

-+--
----
----
-+--

Sample Output

6
1 1
1 3
1 4
4 1
4 3
4 4

题意:有4×4个把手的冰箱,规定转换把手的同时也要转换这一行和列的把手,问给定一个冰箱的把手状态,至少需要转换多少次,能使得冰箱的把手全为open(-)。
思路:一开始想着和POJ1753差不多,遂改了改1753的代码,结果超时了。。

#include <algorithm>
#include <bitset>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>using namespace std;
int map = 0;
int state[16] = {
    4383, 8751, 17487, 34959, 4593, 8946, 17652, 35064,7953, 12066, 20292, 36744, 61713, 61986, 62532, 63624};
int step[16] = {
    0};//得到state数据
void init()
{for (int i = 1; i <= 16; i++){int v = 0, k = 1 << (i - 1);v |= k;int move = 1;for (int j = 4 - (i % 4); j > 0 && j != 4; j--){v |= k << move;++move;}move = 1;for (int j = (i % 4) ? (i % 4 - 1) : 3; j > 0; j--){v |= k >> move;++move;}move = 4;for (int j = (i % 4) ? (3 - i / 4) : (4 - i / 4); j > 0 && j != 4; j--){v |= k << move;move += 4;}move = 4;for (int j = i / 4; j > 0; j--){v |= k >> move;move += 4;}state[i - 1] = v;}
}
//打开第i个冰箱
void flip(int i)
{map ^= state[i];step[i] = !step[i];
}
//判断是否完成
bool check() { return (map == 0xFFFF); }
//寻找解 总共还要开n个门,当前开第i个门
bool find(int n, int i)
{if (n == 0)return check();for (; i < 16; i++){flip(i);if (find(n - 1, i))return true;flip(i); //遍历一种后翻转回来以便下次遍历}return false;
}int times()
{int time = 0;for (int i = 0; i < 16; i++)if (step[i])++time;return time;
}
int main()
{// init();for (int i = 0; i < 4; i++){for (int j = 0; j < 4; j++){map <<= 1;if (getchar() == '-')map |= 1;}getchar();}for (int i = 0; i < 16; i++){if (find(i, 0)){cout << times() << endl;for (int i = 3; i >= 0; i--)for (int j = 3; j >= 0; j--){if (step[i * 4 + j])cout << 4 - i << ' ' << 4 - j << endl;}system("pause");return 0;}}system("pause");return 0;
}

于是又百度了,看到个大神的思路:

先看一个简单的问题,如何把'+'变成'-'而不改变其他位置上的状态?
答案是将该位置(i,j)及位置所在的行(i)和列(j)上所有的handle更新一次,结果该位置被更新了7次,相应行(i)和列(j)的
handle被更新了6次,剩下的被更新了4次.被更新偶数次的handle不会造成最终状态的改变. 
因此得出高效解法,在每次输入碰到'+'的时候,自增该位置与相应的行和列,当输入结束后,遍历数组,所有为奇数的位置则是操作 
的位置,而奇数位置的个数之和则是最终的操作次数.
#include <algorithm>
#include <bitset>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>using namespace std;
int a[4][4] = {
    0};
int main()
{char c;for (int i = 0; i < 4; i++){for (int j = 0; j < 4; j++){cin >> c;if (c == '+'){for (int k = 0; k < 4; k++){//将同行列的都操作一次a[i][k] ^= 1;a[k][j] ^= 1;}a[i][j] ^= 1;}}}int sum = 0;for (int i = 0; i < 4; i++)for (int j = 0; j < 4; j++)if (a[i][j])sum++;printf("%d\n", sum);for (int i = 0; i < 4; i++){for (int j = 0; j < 4; j++){if (a[i][j])printf("%d %d\n", i + 1, j + 1);}}return 0;
}