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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章