Description
有一个4*4的棋盘,放有16枚棋子。
每个棋子都是一面黑一面白,一开始有的黑面朝上,有的白面朝上。
下面是一个例子,这个例子用文字描述为:
bwbw
wwww
bbwb
bwwb
我们可以任选一个棋子,把它自己和它的相邻棋子(上下左右,如果有的话)翻面。
比如在例子中如果我们选第3行第1列的棋子翻面,布局就变成如下:
bwbw
bwww
wwwb
wwwb
题目
求出能把所有棋子都翻成白色或都黑色的最少的步数。
Input
4行每行4个字符,可能是b(黑)或w(白)
Output
一个数,最少步数。如果无解输出Impossible
Sample Input
bwbw
wwww
bbwb
bwwb
Sample Output
Impossible

这道题目是一道典型的 深搜。我们可以用3个参数记录一种状态:

step,x,y;

step即当前状态已经使用的步数,x,y,记当前正在考虑是否翻面的棋子的坐标,但是把x,y传到下一层有些麻烦…我们需要判断,如果y=4,那么就传给下一层(x+1,1),否则传给下一层(x,y+1),因为这里没有考虑到x是否越界,所以在dfs的拓展之前还要判断if(x==5)return;

代码实现。

代码实现一直是有些麻烦的事情,有些思路不及时打下来的话就可能逐渐消退。

根据题意,搜索的终点是所有棋子都朝向同一面,也就是任意棋子的朝向==第一颗的

那么很轻易可以写下check函数:

bool check()
{
for(int i=1;i<=4;i++)
{
for(int j=1;j<=4;j++)
{
if(mp[i][j]!=mp[1][1])return 0;
}
}
return 1;
}

翻面也可以暴力写出来:

int dir[5][2]={{0,0},{0,1},{0,-1},{1,0},{-1,0}};
void fan(int x,int y)
{
for(int i=0;i<5;i++)
{
int tx=x+dir[i][0],ty=y+dir[i][1];
if(in(tx,ty))mp[tx][ty]=back(mp[tx][ty]);
}
}

顺便把判断越界的写好

bool in(int x,int y)
{
return 1<=x&&x<=4&&1<=y&&y<=4;
}

然后就是核心部分—dfs了。

先贴一个模板:

void dfs()//参数用来表示状态
{
if(到达终点状态)
{
...//根据题意添加
return;
}
if(越界或者是不合法状态)
return;
if(特殊状态)//剪枝
return ;
for(扩展方式)
{
if(扩展方式所达到状态合法)
{
修改操作;//根据题意来添加
标记;
dfs();
(还原标记);
//是否还原标记根据题意
//如果加上(还原标记)就是 回溯法
} }
}

1.参数

void dfs(int step,int x,int y)

2.终点状态

if(check()){...}

3.不合法状态

if(x==5)return;

4.剪枝

这道题不需要 awa

5.扩展方式

这道题的扩展方式和模板有点不一样,这个只分两种:翻或者是不翻,但是要注意的是,翻之前要给x,y打上标记,翻完了再取消标记,达到回溯的效果!

fan(x,y);
if(y==4)dfs(step+1,x+1,1);
else dfs(step+1,x,y+1);
fan(x,y); if(y==4)dfs(step,x+1,1);
else dfs(step,x,y+1);
return;

输入的时候最好把原图转换成01矩阵,方便后续操作awa

for(int i=1;i<=4;i++)
{
for(int j=1;j<=4;j++)
{
cin>>ch;
if(ch=='b')
{
mp[i][j]=1;
}
else mp[i][j]=0;
}
}

那个布尔类型的ok是来记是否有解的,如果没有就输出Impossible就可以了。

完整代码贴一下还是:

#include<bits/stdc++.h>
using namespace std;
char ch;
int mp[5][5],/*01矩阵*/min_ans=0x3f3f3f3f,dir[5][2]={{0,0},{0,1},{0,-1},{1,0},{-1,0}};
bool ok;
int back/*反面*/(int x)
{
return (x+1)%2;
}
bool in(int x,int y)
{
return 1<=x&&x<=4&&1<=y&&y<=4;
}
bool check()
{
for(int i=1;i<=4;i++)
{
for(int j=1;j<=4;j++)
{
if(mp[i][j]!=mp[1][1])return 0;
}
}
return 1;
}
void fan(int x,int y)
{
for(int i=0;i<5;i++)
{
int tx=x+dir[i][0],ty=y+dir[i][1];
if(in(tx,ty))mp[tx][ty]=back(mp[tx][ty]);
}
}
void dfs(int step,int x,int y)
{
if(check())
{
min_ans=min(min_ans,step);
ok=1;
return;
}
if(x==5)return; fan(x,y);
if(y==4)dfs(step+1,x+1,1);
else dfs(step+1,x,y+1);
fan(x,y); if(y==4)dfs(step,x+1,1);
else dfs(step,x,y+1);
return;
}
int main()
{
for(int i=1;i<=4;i++)
{
for(int j=1;j<=4;j++)
{
cin>>ch;
if(ch=='b')
{
mp[i][j]=1;
}
else mp[i][j]=0;
}
}
dfs(0,1,1);
if(!ok)
{
cout<<"Impossible"<<endl;
}
else cout<<min_ans<<endl;
return 0;
}

【DFS练习】-翻棋子-C++的更多相关文章

  1. poj—1753 (DFS+枚举)

                                                                                                        ...

  2. 【dfs基础讲解及例题】

    定义 DFS(Depth-First-Search)深度优先搜索算法,是搜索算法的一种. 接下来因为懒得去找大段大段深奥的材料 所以就是一些个人的理解. 所谓深搜,是相对于广搜(只是第一篇)来说的.深 ...

  3. POJ 1753 位运算+枚举

    题意: 给出4*4的棋盘,只有黑棋和白棋,问你最少几步可以使棋子的颜色一样. 游戏规则是:如果翻动一个棋子,则该棋子上下左右的棋子也会翻一面,棋子正反面颜色相反. 思路: 都是暴搜枚举. 第一种方法: ...

  4. poj-3279 poj-1753(二进制枚举)

    题目链接:http://poj.org/problem?id=3279 题目大意: 有一个m*n的棋盘(1 ≤ M ≤ 15; 1 ≤ N ≤ 15),每个格子有两面分别是0或1,每次可以对一个格子做 ...

  5. [UOJ266]Alice和Bob又在玩游戏

    [UOJ266]Alice和Bob又在玩游戏 Tags:题解 作业部落 评论地址 TAG:博弈 题意 不同于树的删边游戏,删掉一个点删去的是到根的路径 题解 这题只和计算\(SG\)有关,博弈的有关内 ...

  6. POJ1753 Flip Game(位运算+暴力枚举)

    Flip game is played on a rectangular 4x4 field with two-sided pieces placed on each of its 16 square ...

  7. 【题解】射击-C++

    Description 不难发现,豆豆能从很多事情中去思考数学,于是豆豆父母决定让他去练习射击,这是项需要集中注意力的运动,相信 能够让豆豆暂时脱离数学.学习射击的第一天就让豆豆产生 了浓厚的兴趣,射 ...

  8. 1753 -- Flip Game

    Flip Game Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 48663   Accepted: 20724 Descr ...

  9. POJ 1753. Flip Game 枚举or爆搜+位压缩,或者高斯消元法

    Flip Game Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 37427   Accepted: 16288 Descr ...

随机推荐

  1. foreach获取索引值

    List<" }; foreach (string item in items) { int index = items.IndexOf(item); Console.WriteLin ...

  2. Windows应用程序文件说明

    bin文件夹:包含debug子目录,含有.exe可执行文件和pdb文件,其中pdb文件包含完整的调试信息(包含函数原型): obj文件夹:包含debug子目录,含有编译过程中生成的中间代码. Prop ...

  3. spring.net的简单使用(四)对象属性注入

    创建了对象,如果是简单对象就到此为止,如果是复杂对象,则需要为它的属性赋值. 属性赋值有两种方法:属性注入和构造器注入. 一.属性注入 在object节点下使用property就是属性注入,如下: & ...

  4. 腾讯网移动端H5页面设计实战分享

    分享 <关于我> 分享  [中文纪录片]互联网时代                 http://pan.baidu.com/s/1qWkJfcS 分享 <HTML开发MacOSAp ...

  5. python中的基本数据类型之字典

    一.字典的简单介绍 字典是(dict)是python中惟一的一个映射类型,他是以{}括起来的键值对组成,在字典中key是唯一的,在保存的时候,根据key来计算出一个内存地址,然后将key-value保 ...

  6. vue+TS(CLI3)

    1.用CLI3创建项目 查看当前CLI的版本,如果没有安装CLI3的  使用npm install --global vue-cli来安装CLI 安装好CLI 可以创建项目了 使用vue create ...

  7. 浅谈jpa、hibernate与spring data jpa三者之间的关系

    1.解释hibernate之前先了解下什么是orm,orm是object relation mapping,即对象关系映射,object可以理解成java实体类Entity,relation是关系型数 ...

  8. 转:Mongoose使用操作

    一般我们不直接用MongoDB的函数来操作MongoDB数据库 Mongose就是一套操作MongoDB数据库的接口.   连接数据库 // mongoose 链接var mongoose = req ...

  9. 写在Logg SAP项目上线之际

    根据大环境大行业的惯用做法,公司建立Logg品牌是在意料之中.毫无意外的,Logg也要上到SAP系统中. 其实按它的业务模式来说上SAP系统并不困难,早在几年前就已经有做过了.无非就是接单不生产,外包 ...

  10. Unity Shader常用函数,标签,指令,宏总结(持续更新)

    极端常用: UnityObjectToClipPos(v.vertex); 最基本的顶点变换,模型空间 ==>裁剪空间 mul(unity_ObjectToWorld, v.vertex); 顶 ...