题目链接:http://poj.org/problem?id=1753

Flip Game
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 46724   Accepted: 20002

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

Source


方法一:

1.对于每一个格子,它都有翻或不翻两种选择,所以枚举从第一个格子开始一直到最后一格,所以总共有2^16种情况(像二叉树)。然而这种方式必须要搜索到最后一个才能作出判断。

2.对于整盘棋,.每次枚举翻一个,第一次有16种选择,第二次有15种选择,所以:16*15*14……。当搜索到符合全白或全黑则直接返回,这种方法较快。

技巧:由于每个棋只有两种情况,则可以讲棋盘压缩成二进制以记录状态。(推导:当单个的情况数为n种时,可以将其状态用n进制记录)。

方法二:

1.枚举第一行的所有状态。

2.如果把所有棋翻为黑色:从第二行开始,如果当前格子的头上格子为白色,那么需要翻转当前格子。因为在这一行之内,只有当前格子能够使头上的格子变为黑色,然后一直递推到最后一行。如果把所有棋翻为白色,做法亦如此。

3.分析:方法二相对于方法一是有明显的优势的:方法二从第二行开始,每翻转一个棋都是有针对性的、有目的性的;而方法一则是枚举所有情况,盲目地翻转,如:假如要把所有棋翻为黑色,而当前格子为黑色,却还是硬要翻转该格子,那显然是行不通的。所以方法二相对来说更“智能”。

4.注意:s&(1<<i)的值要么等于0,要么等于(1<<i);而不是0或1。应注意!!

5.此题的加强版,必须使用方法二:POJ3279:http://www.cnblogs.com/DOLFAMINGO/p/7538582.html

DFS(方法一):

 #include<cstdio>//dfs直接对棋盘进行操作
#include<cstring>
#define MIN(a,b) (a<b?a:b)
#define init_min 2000000000
int a[],min; int get()
{ //获取状态的二进制数表达
int sum = ;
for(int i = ; i<; i++)
sum += a[i]<<i;
return sum;
} void flip(int loc)
{
a[loc] = !a[loc];
if(loc->=) a[loc-] = !a[loc-];
if(loc+<) a[loc+] = !a[loc+];
if(loc%!=) a[loc-] = !a[loc-];
if(loc%!=) a[loc+] = !a[loc+];
} void dfs(int loc,int step)
{
if(loc==)
{ //当搜索到最后一个格子时,开始判断
int status = get();
if(status== || status==(<<)-)
min = MIN(min,step);
} else
{
dfs(loc+,step);
flip(loc);//翻转
dfs(loc+,step+);
flip(loc);//再翻转,使其状态复原
}
} int main()
{
char s[];
for(int i = ; i<; i++)
{
scanf("%s",s);
for(int j = ; j<; j++)
{
if(s[j]=='b') a[i*+j] = ;
else a[i*+j] = ;
}
}
min = init_min;
dfs(,);
if(min!=init_min)
printf("%d\n",min);
else
puts("Impossible");
return ;
}

BFS(方法一):

 #include<cstdio>//由于bfs需要记录状态,而直接用数组入队列会增加时间(stl的原因),所以用二进制数记录,并对其操作
#include<cstring>
#include<queue> using namespace std; int a[],ss,vis[];//ss为初始状态,vis用来标记访问过的状态
struct node
{ //status为棋牌状态,step为步数
int status, step;
}; void calcul(node *now, node *next,int i)
{
if(now->status&(<<i)) next->status -= (<<i);
else next->status += (<<i);
} void turn (node *now, node *next,int i)
{ //翻转时直接对二进制数进行操作,即01
calcul(now, next,i);
if(i->) calcul(now, next,i-);
if(i+<) calcul(now, next,i+);
if(i%!=) calcul(now, next,i-);
if(i%!=) calcul(now, next,i+);
} int bfs()
{
node now, next;
queue<node>q;
now.status = ss, now.step = ; q.push(now);
vis[now.status] = ;
memset(vis,,sizeof(vis));
while(!q.empty())
{
now = q.front(); q.pop();
if(now.status== || now.status==0xffff) return now.step;
for(int i = ; i<; i++)
{ /*之前在这里加了个是否重复翻转的判断,但时间增加了一倍
细想下面的判重已经包含了这个功能*/
next.status = now.status;
turn(&now,&next,i);//翻转
if(vis[next.status]) continue;//判重
next.step = now.step + ;
vis[next.status] = ;
if(next.status== || next.status==0xffff) return next.step;
q.push(next);
}
}
return -;
} int main()
{
char s[];
ss = ;
for(int i = ; i<; i++)
{
scanf("%s",s);
for(int j = ; j<; j++)
{
if(s[j]=='b') { a[i*+j] = ; ss += <<(i*+j);}
else a[i*+j] = ;
}
}
int ans = bfs();
if(ans!=-)
printf("%d\n",ans);
else
puts("Impossible");
return ;
}

方法二:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
#define ms(a,b) memset((a),(b),sizeof((a)))
using namespace std;
typedef long long LL;
const int INF = 2e9;
const LL LNF = 9e18;
const int MOD = 1e9+;
const int MAXN = +; int M[MAXN][MAXN], subM[MAXN][MAXN];
int op[MAXN][MAXN];
int n, m; void press(int x, int y)
{
op[x][y] = ;
subM[x][y] = !subM[x][y];
if(x->=) subM[x-][y] = !subM[x-][y];
if(x+<) subM[x+][y] = !subM[x+][y];
if(y->=) subM[x][y-] = !subM[x][y-];
if(y+<) subM[x][y+] = !subM[x][y+];
} bool all()
{
int b1 = , b2 = ;
for(int i = ; i<; i++)
for(int j = ; j<; j++)
{
if(subM[i][j]==) b1 = ;
if(subM[i][j]==) b2 = ;
}
return b1||b2;
} void solve(int s, int type, int &ans)
{
ms(op, );
memcpy(subM, M, sizeof(subM)); int cnt = ;
for(int i = ; i<; i++)
if( (s&(<<i))==(type<<i) ) press(, i), cnt++;
//注意:s&(1<<i)的值要么等于0,要么等于(1<<i);而不是0或1。应注意!! for(int i = ; i<; i++)
for(int j = ; j<; j++)
if(subM[i-][j]==type) press(i, j), cnt++; if(all())
ans = min(ans, cnt);
} int main()
{
char s[];
for(int i = ; i<; i++)
{
scanf("%s",s);
for(int j = ; j<; j++)
{
if(s[j]=='b') M[i][j] = ;
else M[i][j] = ;
}
} int ans = INF;
for(int s = ; s<(<<); s++)
{
solve(s, , ans); //尝试把棋全部翻成0
solve(s, , ans); //尝试把棋全部翻成1
}
if(ans!=INF)
printf("%d\n", ans);
else
puts("Impossible");
}

poj1753 Flip Game —— 二进制压缩 + dfs / bfs or 递推的更多相关文章

  1. hdu 5335 Walk Out(bfs+斜行递推) 2015 Multi-University Training Contest 4

    题意—— 一个n*m的地图,从左上角走到右下角. 这个地图是一个01串,要求我们行走的路径形成的01串最小. 注意,串中最左端的0全部可以忽略,除非是一个0串,此时输出0. 例: 3 3 001 11 ...

  2. EOJ Problem #3249 状态压缩+循环周期+反向递推

    限量供应 Time limit per test: 4.0 seconds Time limit all tests: 4.0 seconds Memory limit: 256 megabytes ...

  3. poj1753(位运算压缩状态+bfs)

    题意:有个4*4的棋盘,上面摆着黑棋和白旗,b代表黑棋,w代表白棋,现在有一种操作,如果你想要改变某一个棋子的颜色,那么它周围(前后左右)棋子的颜色都会被改变(白变成黑,黑变成白),问你将所有棋子变成 ...

  4. poj1753 Flip Game(BFS+位压缩)

    题目链接 http://poj.org/problem?id=1753 题意 一个棋盘上有16个格子,按4×4排列,每个格子有两面,两面的颜色分别为黑色和白色,游戏的每一轮选择一个格子翻动,翻动该格子 ...

  5. POJ-3279.Fliptile(二进制状态压缩 + dfs) 子集生成

    昨天晚上12点刷到的这个题,一开始一位是BFS,但是一直没有思路.后来推了一下发现只需要依次枚举第一行的所有翻转状态然后再对每个情况的其它田地翻转进行暴力dfs就可以,但是由于二进制压缩学的不是很透, ...

  6. DFS/BFS+思维 HDOJ 5325 Crazy Bobo

    题目传送门 /* 题意:给一个树,节点上有权值,问最多能找出多少个点满足在树上是连通的并且按照权值排序后相邻的点 在树上的路径权值都小于这两个点 DFS/BFS+思维:按照权值的大小,从小的到大的连有 ...

  7. 【DFS/BFS】NYOJ-58-最少步数(迷宫最短路径问题)

    [题目链接:NYOJ-58] 经典的搜索问题,想必这题用广搜的会比较多,所以我首先使的也是广搜,但其实深搜同样也是可以的. 不考虑剪枝的话,两种方法实践消耗相同,但是深搜相比广搜内存低一点. 我想,因 ...

  8. ID(dfs+bfs)-hdu-4127-Flood-it!

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4127 题目意思: 给n*n的方格,每个格子有一种颜色(0~5),每次可以选择一种颜色,使得和左上角相 ...

  9. [LeetCode] 130. Surrounded Regions_Medium tag: DFS/BFS

    Given a 2D board containing 'X' and 'O' (the letter O), capture all regions surrounded by 'X'. A reg ...

随机推荐

  1. 【前端阅读】——《编程之魂》摘记&读后感&思维导图

    前言:这本书全名叫<编程之魂——与27为编程语言创始人对话>,它的内容以采访对话为主,以图通过和顶级大师的真实交流来调查:大师们为什么要创建某种编程语言,它的技术如何开发.如何教授和学习, ...

  2. 【前端阅读】——《JavaScript应用开发技术详解指南》摘记&思维导图

    读这本书,我主要关注三个部分:JavaScript内置函数,程序调试以及Ajax基础.由于多是介绍基本概念,所以,采用思维导图的方式,做了一个梳理,以下就是精简的主要内容. 注:转载请注明出处

  3. Loadrunner 使用过程常见问题

    一.安装配置 解决LoadRunner参数化最多读取100个值数据限制的问题. 修改.\Program Files\HP\LoadRunner\config\ vugen.ini中[ParamTabl ...

  4. 接口测试 rest-assured 使用指南

    转自:https://testerhome.com/topics/7060 原文:https://github.com/rest-assured/rest-assured/wiki/Usage本文gi ...

  5. Vue2.0 :key作用

    转自:https://www.cnblogs.com/zhumingzhenhao/p/7688336.html 为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需 ...

  6. 从有序数组中查找某个值 low_bound

    二分搜索 题意: 给定长度为n的单调不下降数列a0, ...an-1和一个数k,求满足ai>=k条件的最小的i. 不存在的情况下输出n. 输入: 5        3 2 3 3 5 6 输出: ...

  7. SpringBoot学习之启动方式

    1.通过@SpringBootAppliction注解类启动 启动方法:找到注解类->鼠标右键->run as-> java application. 2 通过maven启动Spri ...

  8. 系统安全-Google authenticator

    对于某些人来说,盗取密码会比你想象的更简单  以下任意一种常见的操作都可能让你的密码面临被盗的风险: 在多个网站上使用同一个密码 从互联网上下载软件 点击电子邮件中的链接 两步验证可以将别有用心的人阻 ...

  9. Android - 单例模式(singleton)的使用

    单例模式(singleton)的使用 本文地址:http://blog.csdn.net/caroline_wendy 单例(singleton)是特殊的Java类,在创建实例时.一个类仅同意创建一个 ...

  10. C#中方法中 ref 和 out的使用

    案例1: static void Main() { , , , }; int numLargerThan10,numLargerThan100,numLargerThan1000 ; Proc(ary ...