您的位置:首页 > 其它

poj2965 The Pilots Brothers' refrigerator

2018-03-09 23:22 316 查看
he Pilots Brothers’ refrigerator

Time Limit: 1000 ms / Memory Limit: 65536 kb

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 closed. The refrigerator is open only when all handles are open. The handles are represented as a 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

Source

None

第一种解法,就是bfs+状态压缩,和我做的上道题十分类似,一直超时,这也让我学到了怎么用打表来减少时间,真的特别妙

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
#define N (1<<16)
typedef struct Node{
int i,j;//代表扳动的哪个开关变成当前这个状态
int front;//表示前面那个状态
int count;//代表扳动了几个棋子
bool visit;//防止反复出现该状态
}Node;
//这种打表思想来解决超时问题,真的太牛逼了
int flip[4][4] = {63624, 62532, 61986, 61713, 36744, 20292, 12066, 7953, 35064, 17652, 8946, 4593, 34959, 17487, 8751, 4383};
typedef struct num{
int a,b;
friend bool operator < (const num &p,const num &q)
{
if(p.a == q.a)
return p.b < q.b;
else
return p.a < q.a;
}
}num;
Node node[N + 1];
bool check(int i,int j)
{
if(i < 0 || i > 3)
return false;
if(j < 0 || j > 3)
return false;
return true;
}
int main()
{
//cout << N << endl;
for(int i = 0;i <= N;++i)
{
node[i].i = node[i].j = node[i].front = -1;
node[i].count = 0;
node[i].visit = false;
}
int n = 0;
for(int i = 0;i < 16;++i)
{
char s;
cin >> s;
n *= 2;
if(s == '+')
n += 1;
}
//cout << n << endl;
queue<int>que;
que.push(n);
node
.visit = true;
int flag = -1;
while(!que.empty() && flag == -1)
{
int t = que.front();
que.pop();
for(int i = 0;i < 4;++i)
{
for(int j = 0;j < 4;++j)
{
int m = t ^ flip[i][j];
//如果要用下面的程序,每一次都要一位一位的进行异或,很费时间,当用打表出来的数,就可以直接异或将行列翻转
/*int pos = 4 * i + j;
m ^= (1 << (15 - pos));
for(int a = 0;a < 4;++a)
{
if(check(i,a) && a != j)
m ^= (1 << (15 + (j - a) - pos));
}
for(int a = 0;a < 4;++a)
{
if(check(a,j) && a != i)
m ^= (1 << (15 + 4 * (i - a) - pos));
}*/
//cout << m << " " << (t ^ flip[i][j]) << endl;
node[m].count = node[t].count + 1;
if(m == 0)
{
cout << node[m].count << endl;
flag = 0;
}
//相当于剪枝吧,接下来遍历的状态出现过,就不放到队列里了
if(node[m].visit == false)
{
node[m].visit = true;
node[m].i = i;
node[m].j = j;
node[m].front = t;
que.push(m);
}
}
}
}
int x = flag;
num ptr[17];
int k = 0;
while(node[x].front != -1)
{
ptr[k].a = node[x].i;
ptr[k++].b = node[x].j;
x = node[x].front;
}
for(int i = k - 1;i >= 0;--i)
{
printf("%d %d\n",ptr[i].a + 1,ptr[i].b + 1);
}
/*int x = flag;
num ptr
;
int k = 0;
while(node[x].front != -1)
{
ptr[k].a = node[x].i;
ptr[k++].b = node[x].j;
x = node[x].front;
//cout << x << endl;
}
sort(ptr,ptr + k);
for(int i = 0;i < k;++i)
{
cout << ptr[i].a + 1 << " " << ptr[i].b + 1 << endl;
}*/
return 0;
}


第二种解法来自大神,高手,神高效的解法,要使一个为’+’的符号变为’-‘,如果’+’位置对应的行和列上每一个位置都进行一次操作(就是对应行列开变关,关变开),则整个图只有这一’+’位置的符号改变,其余都不会改变.将翻转的个数成为操作数

首先要将初始状态的+号都变为-号,就是所在行列的每个位置都进行一次操作

然后对所有开关的操作数对2取余((因为一个点进行偶数次操作的效果和没进
cb02
行操作一样,这就是楼上说的取反的原理),所以操作数为奇数的最小步骤中要扳动的开关

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char s[4][4];
bool mark[4][4];
typedef struct Node{
int a,b;
}Node;
int main()
{
memset(mark,false,sizeof(mark));
for(int i = 0;i < 4;++i)
{
cin >> s[i];
}
for(int i = 0;i < 4;++i)
{
for(int j = 0;j < 4;++j)
{
if(s[i][j] == '+')
{
mark[i][j] = !mark[i][j];
for(int k = 0;k < 4;++k)
{
mark[i][k] = !mark[i][k];
mark[k][j] = !mark[k][j];
}
}
}
}
int k = 0;
Node node[17];
for(int i = 0;i < 4;++i)
{
for(int j = 0;j < 4;++j)
{
if(mark[i][j] == true)
{
node[k].a = i;
node[k++].b = j;
}
}
}
cout << k << endl;
for(int i = 0;i < k;++i)
{
cout << node[i].a + 1 << " " << node[i].b + 1 << endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: