`
lingyibin
  • 浏览: 190927 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

POJ1753-位操作

UP 
阅读更多

Flip Game
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 11333 Accepted: 4818

Description

Flip game is played on a rectangular 4x4 field with two-sided pieces placed on each of its 16 squares. One side of each piece is white and the other one is black and each piece is lying either it's black or white side up. Each round you flip 3 to 5 pieces, thus changing the color of their upper side from black to white and vice versa. The pieces to be flipped are chosen every round according to the following rules: 
  1. Choose any one of the 16 pieces. 
  2. Flip the chosen piece and also all adjacent pieces to the left, to the right, to the top, and to the bottom of the chosen piece (if there are any).

Consider the following position as an example: 

bwbw 
wwww 
bbwb 
bwwb 
Here "b" denotes pieces lying their black side up and "w" denotes pieces lying their white side up. If we choose to flip the 1st piece from the 3rd row (this choice is shown at the picture), then the field will become: 

bwbw 
bwww 
wwwb 
wwwb 
The goal of the game is to flip either all pieces white side up or all pieces black side up. You are to write a program that will search for the minimum number of rounds needed to achieve this goal. 

Input

The input consists of 4 lines with 4 characters "w" or "b" each that denote game field position.

Output

Write to the output file a single integer number - the minimum number of rounds needed to achieve the goal of the game from the given position. If the goal is initially achieved, then write 0. If it's impossible to achieve the goal, then write the word "Impossible" (without quotes).

Sample Input

bwwb
bbwb
bwwb
bwww

Sample Output

4

 

 

 

这是原题。

 

本题如果定义一个数组的话,遍历并判断状态 将是一件费时的事,此时可以想到用位来操作。

先讲一些位操作的基本知识:

int test = 0;

C中,int 有2个字节,C++/Java等语言中有4个字节,而一个字节有8位。

要使test的第一位变成1,则可做一个或运算:test | 1, 第二位变成1,则可这样:test | (1 << 1), 第三位变1,则:test | (1 << 2)。把某位变成0可以用与、非运算,如把第三位变成0,则test & ~(1 << 2) 。可以写一个程序试试:

 

#include<iostream>
using namespace std;

int main()
{
	int a = 1, b = 7; //7用2进制表示是111
	b &= ~(a <<2);
	cout<<b<<endl; //输出结果为3,用2进制表示是11
	return 0;
}

 要把两个数的各个位合并(就是有1即1),可用或运算,给一个示例:

 

	int a = 5, b = 3;
	a |= b;
	cout<<a<<endl; //答案7

 把两个数的各个位相减,用抑或或运算,示例:

 

	int a = 5, b = 3;
	a ^= b;
	cout<<a<<endl; //答案:6

 ……之后还遇到什么位运算再补充。。。

 

本题 可用16位来表示各个状态,两位一个,用1来表示black,0表示white。则65536是全black的情况,0是全白的情况,这样的话,要判断是否已经得出结果时,就不用遍历16个元素了!!!

如本题:

bwwb

bbwb

bwwb

bwww

状态值为6585,计算方法为

1*2^0+0*2^1+0*2^2..1*2^12+0*2^13..=6585

下面是网上摘取的一段代码,呵呵,写得比我的好,转此来学习。

 

在此基础上进行BFS搜索,首先理解一点,先点(0,0)再点(0,1)与先点(0,1)再点(0,0)对结果不造成任何影响.因此遍历棋盘的16个位置,将每次点击后的状态id利用树状结构保存.如:

                                  6585

                               /     |      \  ...

                           (0,0) (0,1)  (0,2)

                            /        |         \  ...

                         6568   6553   6646

                      ...............................

对此树进行BFS搜索,将id为0(全白)或65535(全黑)的时候则搜索成功,输出树的高度,否则输出"Impossible".

为了提高搜索效率,采用位运算,如果想将整数的二进制某一位翻转可采用id^=(1<<x)(x代表要翻转的位置)


 

#include "assert.h"
#include <iostream>
#include <queue>
using namespace std;

const int MAX_STATE = 65536;
const int ALL_WHILE_STATE = 0;
const int ALL_BLACK_STATE = 65535;
const int WIDTH_OF_BOARD = 4;
const int SIZE_OF_BOARD = WIDTH_OF_BOARD * WIDTH_OF_BOARD; // 4 * 4

int ConvertPieceColorToInt(char color)
{
    switch(color)
    {
    case 'b':
        return 1;
    case 'w':
        return 0;
    }
}

int FlipPiece(int state_id, int position)
{
    state_id ^= (1 << position);

    // up
    if(position - 4 >= 0)
        state_id ^= (1 << (position - 4));
    // down
    if(position + 4 < SIZE_OF_BOARD)
        state_id ^= (1 << (position + 4));
    // left
    if(position % 4 != 0)
        state_id ^= (1 << (position - 1));
    // right
    if(position % 4 != 3)
        state_id ^= (1 << (position + 1));

    return state_id;
}

int main()
{
    int current_state_id = 0;
    int state[MAX_STATE];
    queue<int> search_queue;

    memset(state, -1, sizeof(state));

    char color;

    for(int i = 0; i < SIZE_OF_BOARD; ++i)
    {
        cin >> color;
        current_state_id += ConvertPieceColorToInt(color) << i;
    }

    if(current_state_id == ALL_WHILE_STATE
        || current_state_id == ALL_BLACK_STATE)
    {
        cout << "0" << endl;
        return 0;
    }

    state[current_state_id] = 0;
    search_queue.push(current_state_id);

    int next_state_id;

    while(!search_queue.empty())
    {
        current_state_id = search_queue.front();
        search_queue.pop();

        for(int i = 0; i < SIZE_OF_BOARD; ++i)
        {
            next_state_id = FlipPiece(current_state_id, i);
            if(next_state_id == ALL_WHILE_STATE
                || next_state_id == ALL_BLACK_STATE)
            {
                cout << state[current_state_id] + 1 << endl;
                return 0;
            }
            assert(next_state_id < MAX_STATE);
            if(state[next_state_id] == -1 /* not visited */)
            {
                state[next_state_id] = state[current_state_id] + 1;
                search_queue.push(next_state_id);
            }
        }
    }

    cout << "Impossible" << endl;
    return 0;
}
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics