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
", sum);
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
if (a[i][j])
printf("%d %d
", i + 1, j + 1);
}
}
return 0;
}