POJ 1753
2016-03-02 21:19
246 查看
描述
4*4的方格棋盘,每个棋子有白面和黑面,每个方格中的棋子为白/黑,每轮翻3~5个棋子改变它们的颜色,每轮根据以下规则选择翻面的棋子:1. 选择16个棋子中的任一个
2. 翻转已选棋子的邻近棋子(左、右、上、下,四个邻近的棋子,如果有就翻)
示例:
bwbbwwbwbwwwwwbb
b为黑,w为白,若翻第三行第一个,则棋盘变成:
bbwwwwwwbwwwwwbb
目标是把所有棋子全都白面向上或全都黑面向上,求达成目标的最少回合。
输入
4行,每行4个字符,”w”或”b”,表示给定的棋盘当前状态输出
从棋盘当前状态达成目标所需的最少游戏回合,若当前已达成目标,输出0,若不可能实现,则输出”Impossible”(不输出引号)样例输入
bwwbbbwb
bwwb
bwww
样例输出
4参考
(1)bfs:http://changgongxiaorong.cn/?p=23(2)dfs:http://blog.csdn.net/freezhanacmore/article/details/8142014
(3)位运算:http://www.it610.com/article/1987880.htm
根据参考1、参考2用广度搜索和深度搜索都可。
c++实现
(1)广度搜索版
参考1的思路:广度搜索+枚举+位运算
一个棋子有两种情况,16个棋子,即棋盘有2^16方种情况,即65536种情况,正好一个短整形,所以想到用一个短整形记录棋盘情况,16个位对应棋盘16格,0和1表示黑和白。当状态为0或65535时表示说明全是‘b’或‘w’.
广度搜索使用非递归模式,速度快,用队列实现,元素短整形。全部遍历一遍,剪枝掉重复搜索的情况。
代码:
532K 16MS
#include <iostream> using namespace std; const int MAX = 65535;//[0, 65535]共65536种情况 unsigned short myqueue[MAX];//用‘位’保存状态的数组 int myrear = 0, mytop = 0;// 头尾指针 bool flag[MAX];//是否出现过 int num[MAX];//记录翻拍次数 /** 初始化,w为0,b为1,拼接成16位数字 */ void init(){ unsigned short temp = 0; char c; for (int i = 0; i < 16; ++i) { cin >> c; //1左移i位,为当前黑色位置,temp为现有棋盘,temp不断与新数字按位与,生成倒序的棋盘 if(c == 'b'){ temp |= (1 << i); } } myqueue[myrear++] = temp; //追加新的状态 flag[temp] = true; //该状态已经有过 } /**now为当前状态,i为要翻转的棋子序号[0,15]*/ unsigned short change(unsigned now, int i){ unsigned short temp = 0; temp |= (1 << i); //temp为当前要改变颜色的位置 // 翻转相邻的四个棋子 if((i+1)%4 != 0){ //该棋子不是最右边 temp |= (1 << (i+1)); } if(i%4 != 0){ // 不是最左边 temp |= (1 << (i-1)); } if(i > 3){ // 不是最上边 temp |= (1 << (i-4)); } if(i < 12){ // 不是最上面 temp |= (1 << (i+4)); } return now ^ temp; // 旧状态和新状态相同为0,不同为1 } bool bfs(){ // 遍历现有的状态 while(myrear > mytop){ // 前一个状态 unsigned short former = myqueue[mytop++]; for (int i = 0; i < 16; ++i) { unsigned short temp = change(former, i); if(former == 0 || former == 65535){ cout << num[former]; // 全黑或全白了 return true; } else if (!flag[temp]) //状态未出现过,剪枝 { myqueue[myrear++] = temp; flag[temp] = true; num[temp] = num[former] + 1; // 每个记录的是当前状态是总共经历了多少次翻牌次数 } } } return false; } int main() { init(); if(!bfs()){ cout << "Impossible"; } return 0; }
(2)深度搜索版
参考2的思路:每次遇到下一个方格有两种处理方法,要么翻转,要么不翻转。
若不翻转方格,则直接处理下一个方格,翻转的方格数不再增加,
若翻转当前方格,则还要翻转相邻的四个方格,然后再处理下一个方格,翻转的总数+1。
相关文章推荐
- 初学ACM - 组合数学基础题目PKU 1833
- POJ ACM 1001
- POJ ACM 1002
- 1611:The Suspects
- POJ1089 区间合并
- POJ 2635 The Embarrassed Cryptographe
- POJ 3292 Semi-prime H-numbers
- POJ 2773 HAPPY 2006
- POJ 3090 Visible Lattice Points
- POJ-2409-Let it Bead&&NYOJ-280-LK的项链
- POJ-1695-Magazine Delivery-dp
- POJ1523 SPF dfs
- POJ-1001 求高精度幂-大数乘法系列
- POJ-1003 Hangover
- POJ-1004 Financial Management
- 用单调栈解决最大连续矩形面积问题
- 2632 Crashing Robots的解决方法
- 1573 Robot Motion (简单题)
- POJ 1200 Crazy Search(简单哈希)
- 【高手回避】poj3268,一道很水的dijkstra算法题