1. 程式人生 > >Fliptile POJ - 3279 開關反轉問題 + 位運算

Fliptile POJ - 3279 開關反轉問題 + 位運算

解這題的關鍵思想

第一行的狀態決 定了後面所有行的狀態

奶牛踏瓷磚問題,顯然奶牛踏 1 次和奶牛踏3次,效果是一樣的,那麼每塊瓷磚的翻轉次數,只可能是 0次或一次。

那麼現在問題就轉換成了列舉結果矩陣中的每一個數值是 1 還是0 ,但是 M 和 N 的最大值為 15,單純暴力的話,2^15*15 一定會超時。

問題的關鍵在於前一行的狀態決定了後一行的狀態,所以一旦第一行確定,後面的所有行就確定了。現在就可以轉化成單純的列舉每一行或者每一列。 時間複雜度 2^15 ,很小。

起始狀態                                          踏瓷磚次數矩陣
1 0 0 1                                              0 0 0 0
0 1 1 0                                              1 0 0 1
0 1 1 0                                              1 0 0 1
1 0 0 1                                              0 0 0 0

我實現的程式碼就是 列舉第一列的狀態 ,計算出踏瓷磚的狀態矩陣,判斷最後該情況是否可取,因為照這種前一列推後一列的狀態,最後一列的狀態不一定是全0,所以要判斷一下。

程式碼如下:

#include<iostream>
#include<cstring>

using namespace std;
int statu[20];
int m,n;
int maze[20][20];
int result[20][20];   //儲存最終結果
int mid[20][20];      //儲存列舉的結果
int mid_maze[20][20]; //儲存中間變化的迷宮
int dir[4][2] = {{0,1},{0,-1},{1,0},{-1,0}};
int max_time;
void flip(int x,int y)
{
    mid_maze[x][y]  = (mid_maze[x][y]+1)%2;

    for(int i=0;i<4;i++)
    {
        int px =x+dir[i][0];
        int py = y+dir[i][1];
        if(px<0||py<0||px>=m||py>=n) continue;
        mid_maze[px][py]  = (mid_maze[px][py]+1)%2;
    }
}
int hasre;
int main()
{
    ios::sync_with_stdio(false);
    while(cin>>m>>n)
    {
        hasre=0;
        memset(mid_maze,0,sizeof(mid_maze));
        memset(maze,0,sizeof(maze));

        max_time = 0x3f3f3f3f;
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                cin>>maze[i][j];
            }
        }

        for(int pp=0; pp< 2<<n;pp++)
        {

                int counts = 0;
                int p =pp;
                memset(statu,0,sizeof(statu));
                memset(mid,0,sizeof(mid));

                while(p!=0)
                {
                    statu[counts++] = p&1;
                    p = p>>1;
                }


                for(int i=0;i<m;i++)
                    for(int j=0;j<n;j++)
                        mid_maze[i][j] = maze[i][j];

                counts =0;
                for(int i=0;i<n;i++)
                {
                    mid[0][i] = statu[i];
                    if(statu[i])
                    {
                        flip(0,i);
                        counts++;
                    }
                }

                for(int i=1;i<m;i++)
                {
                    for(int j=0;j<n;j++)
                    {
                        if(mid_maze[i-1][j] ==1)
                        {
                            mid[i][j]=1;
                            flip(i,j);
                            counts++;
                        }
                    }
                }
                int ops=1;
                for(int i=0;i<n;i++)
                {
                    if(mid_maze[m-1][i]==1)
                    {
                        ops=0;
                        break;
                    }
                }

                if(ops==0)continue;

                if(counts < max_time)
                {
                    max_time = counts;
                    hasre=1;
                    for(int i=0;i<m;i++)
                    {
                        for(int j=0;j<n;j++)
                        {
                            result[i][j] = mid[i][j];
                        }
                    }
                }else if(counts == max_time){

                    int flag=0;
                    for(int i=0;i<m;i++)
                    {
                        for(int j=0;j<n;j++)
                        {
                            if(result[i][j] > mid[i][j])
                            {
                                break;
                                flag=1;
                            }
                        }
                        if(flag==1)break;
                    }

                    if(flag ==1)
                    {
                        hasre =1;
                        for(int i=0;i<m;i++)
                        {
                            for(int j=0;j<n;j++)
                            {
                                result[i][j] = mid[i][j];
                            }
                        }
                    }


                }

        }
        if(hasre ==0)
        {
            cout<<"IMPOSSIBLE"<<endl;
            continue;
        }


        for(int i=0;i<m;i++)
        {
            cout<<result[i][0];
            for(int j=1;j<n;j++)
            {
                cout<<" "<<result[i][j];
            }
            cout<<endl;
        }


    }
    return 0;
}

最後附上一個網上大牛用該題寫的小遊戲
https://pan.baidu.com/s/1czj69yuvMVf_b7IbSOm-ig