1.青蛙跳杯子
【问题描述】
X星球的流行宠物是青蛙,一般有两种颜色:白色和黑色。
X星球的居民喜欢把它们放在一排茶杯里,这样可以观察它们跳来跳去。
如下图,有一排杯子,左边的一个是空着的,右边的杯子,每个里边有一只青蛙。
*WWWBBB
其中,W字母表示白色青蛙,B表示黑色青蛙,*表示空杯子。
X星的青蛙很有些癖好,它们只做3个动作之一:
1. 跳到相邻的空杯子里。
2. 隔着1只其它的青蛙(随便什么颜色)跳到空杯子里。
3. 隔着2只其它的青蛙(随便什么颜色)跳到空杯子里。
对于上图的局面,只要1步,就可跳成下图局面:
WWW*BBB
本题的任务就是已知初始局面,询问至少需要几步,才能跳成另一个目标局面。
输入为2行,2个串,表示初始局面和目标局面。
输出要求为一个整数,表示至少需要多少步的青蛙跳。
例如:
输入:
*WWBB
WWBB*
则程序应该输出:
2
再例如,
输入:
WWW*BBB
BBB*WWW
则程序应该输出:
10
我们约定,输入的串的长度不超过15
----------------------------
笨笨有话说:
我梦见自己是一棵大树,
青蛙跳跃,
我就发出新的枝条,
春风拂动那第 5 层的新枝,
哦,我已是枝繁叶茂。
【问题分析】
从一种状态到另一种状态,求需要的最小步数,这个时候就要想到可能会用到BFS求解。在数据结构的图遍历中,BFS是借助队列来实现的,但是图的节点都是固定的已知的。而在这个题目中,状态(点)是随机生成的。比如当前青蛙的状态使*wwbb,那么在这种状态下,所有可能的下一个串就相当于相邻的节点,然后将其入队列。
【代码展示】
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <queue>
#include <map>
#include <cmath>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int MAXN = 20;
int dir[6]={-1,-2,-3,1,2,3};//定义青蛙可能跳跃的方向
//定义结构体
struct Node{
string s;//青蛙当前的状态
int step;//达到s这种状态所需要的步数
int pos;//"*"所在的位置
Node(string ss, int step1, int pos1){
s=ss;
step=step1;
pos=pos1;
}
Node(){
}
};
queue<Node> myqueue;//定义队列
map<string,int> mymap;//防止状态重复
string str,ans;//表示起始状态的字符串
void BFS(){
int len = str.size();//获取长度
int pos = str.find('*');//获取'*'所在的位置
Node p = Node(str,0,pos);//初始化表示青蛙开始状态信息的结构体
myqueue.push(p);//入栈!
mymap[str]=1;//记录已经存在
while(!myqueue.empty()){//队列不为空
//
Node temp;
p = myqueue.front();//获取队头元素
myqueue.pop();//出队列
if(p.s==ans){ //找到答案
cout<<p.step<<endl;//输出步数
return;
}
for(int i=0;i<6;i++){//后序节点是动态生成的!!!!!
temp.pos=p.pos+dir[i];//新状态中,*所在的位置
string s_temp=p.s;//
if(temp.pos<0||temp.pos>=len){
continue;//不满足条件,重来
}
swap(s_temp[temp.pos],s_temp[p.pos]);//青蛙跳哈哈哈哈哈哈
temp.s=s_temp;//将新状态赋给
temp.step=p.step+1;//步数加一
if(mymap[temp.s]!=1){ //未出现过的状态才如队列
myqueue.push(temp);
mymap[temp.s]=1;
}
}
}
}
int main(){
cin>>str>>ans;
BFS();
}