The Pilots Brothers' refrigerator 【POJ--2965】

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.


题意:开冰箱,这个冰箱门上有4*4个开关,'-'表示开关是开着的,'+'表示开关是关着的,只有当所有的开关都是开着的这个冰箱才能打开,当你改变任意一个开关状态时,这个开关所在行和所在列的其他开关也跟着改变状态,求使得打开冰箱的最少步数并记录所改变状态的开关位置。


思路:同POJ--1753题的思路差不多,最多需要改变状态的开关个数才2^16-1个,所以直接用枚举方法对每个位置都改变一下状态看是否满足题目要求即可。

          1.用bool型二维数组去存储当前所有开关的状态。

          2.因为要记录所改变状态的开关位置所以要用DFS。求最短步数的同时用一个数组模拟栈去记录所改变状态的开

             关位置。

          3.每改变一个位置就去判断此时是否能打开冰箱。


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

<span style="font-size:18px;">#include <iostream>
#include <cstring>
#include <queue>
#include <cstdio>
using namespace std;
struct node
{
    int x,y;
};
node solve[65540];
bool st[10][10],flag;
int top;
bool isopen()                          //判断当前情况是否可以打开冰箱门
{
    for(int i=0;i<4;i++)
        for(int j=0;j<4;j++)
    {
        if(st[i][j])
            return false;
    }
    return true;
}
void dfs(int i,int j)
{
    if(isopen())
    {
        flag=true;                      //如果已符合要求,进行标记,则可以不用继续搜索直接返回上一层即可
        return ;
    }
    if(i>3)                                 //表示已到达边界
        return ;
    if(j>=3)                              //不改变(i,j)位置的开关状态
    {                                        //如果该行已枚举完则开始枚举下一行
        dfs(i+1,0);
        if(flag)
            return ;
    }
    else
    {
        dfs(i,j+1);
        if(flag)
            return ;
    }
    st[i][j]=!st[i][j];                     //改变(i,j)位置的开关状态
    for(int p=0;p<4;p++)
    {
        st[i][p]=!st[i][p];
        st[p][j]=!st[p][j];
    }
    solve[top].x=i;                    //记录位置
    solve[top].y=j;
    top++;
    if(j>=3)                               //继续下一个位置的枚举
    {
        dfs(i+1,0);
        if(flag)
            return ;
    }
    else
    {
        dfs(i,j+1);
        if(flag)
            return ;
    }
    st[i][j]=!st[i][j];                     //DFS后,回溯的时候要将状态再变回原状态
    for(int p=0;p<4;p++)
    {
        st[i][p]=!st[i][p];
        st[p][j]=!st[p][j];
    }
    top--;                                  //所记录的位置也要删掉
}
int main()
{
    char ch[10];
    for(int i=0;i<4;i++)
    {
        scanf("%s",ch);
        for(int j=0;j<4;j++)               //将输入的字符串转换为bool型的二维数组去存储当前所有开关的状态
        {
            st[i][j]=(ch[j]=='-'?0:1);
        }
    }
    flag=false;                               //标记冰箱是否已经可以打开
    top=0;                                     //初始化步数
    dfs(0,0);
    printf("%d\n",top);
    for(int i=0;i<top;i++)
        printf("%d %d\n",solve[i].x+1,solve[i].y+1);
    return 0;
}
</span>

当然,还有一种更巧妙的方法!!!


思路:如果你要改变某一位置的开关状态,你只需将该位置所在行所在列的每一个位置按题目要求都改变一次,你会发现只有该位置改变的状态,该位置所在行所在列的其他位置都没有改变状态,不信你可以手动模拟一下。那么你只需用一个char型的二维数组(用来存储最初所有开关的状态)和一个bool型的二维数组(用来进行改变开关状态的记录),将所有char型数组内的'+'都改变之后,这个bool型数组内留有多少个1,就说明最少需要多少步才能使冰箱打开,而且1所在的位置即所需改变状态的开关位置。


#include <iostream>
#include <cstring>
#include <queue>
#include <cstdio>
using namespace std;
char st[10][10];
bool ch[10][10];
int main()
{
    memset(st,0,sizeof(st));
    memset(ch,0,sizeof(ch));
    for(int i=0; i<4; i++)
        scanf("%s",st[i]);
    for(int i=0; i<4; i++)
        for(int j=0; j<4; j++)
        {
            if(st[i][j]=='+')                       //只要是需要改变状态的开关就对该行该列的所有位置都进行一边状态改变
            {
                ch[i][j]=!ch[i][j];     
                for(int p=0; p<4; p++)
                {
                    ch[i][p]=!ch[i][p];
                    ch[p][j]=!ch[p][j];
                }
            }
        }
    int cnt=0;
    for(int i=0; i<4; i++)                       //累加所需改变的步数
        for(int j=0; j<4; j++)
            if(ch[i][j])
                cnt++;
    printf("%d\n",cnt);
    for(int i=0; i<4; i++)                      //输出所需改变的开关位置
        for(int j=0; j<4; j++)
            if(ch[i][j])
                printf("%d %d\n",i+1,j+1);
    return 0;
}


发布了187 篇原创文章 · 获赞 15 · 访问量 7万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章