黑白子交换

来源:互联网 发布:李小冉 知乎 编辑:程序博客网 时间:2024/05/22 14:33
这一题我在网上找了有好久了,写的人并不多,可能时因为太简单了吧—_—||,不过我是好不容易才写好。思路应该还是清晰,就是没有讨巧的方法,是将每一种出现的可能都列了出来。如果大家写出了精简的代码还不吝赐教。


问题描述:
有三个白子和三个黑子如下图布置:
○○○. ● ● ●


游戏的目的是用最少的步数将上图中白子和黑子的位置进行交换:
● ● ● . ○○○


游戏的规则是:(1)一次只能移动一个棋子; (2)棋子可以向空格中移动,也可以跳过一个对方的棋子进入空格,但不能向后跳,也不能跳过两个子。请用计算机实现上述游戏。
***思路分析***
1)棋子表示:用0表示白子,1表示黑子,用char类型数组存放棋子char Array[7]={ '0','0','_','0','1','1','1' };             
如果用char类型的汉字表示,就不太方便了,因为汉字在机内码里用的是两个字节。har为1个字节;
1)游戏规则理解:本题说每次只能移动一个棋子,而棋子可以向空格移动,可以跳过一个对方的棋子进入空格且不能后退,不能跳过两个棋子,要求用的是最少步数。其实我们根据题意就可以理解:所谓的最少步数,只有你能够将黑白子交换位置就是最小步数,因为空格只有一个,而且不能后退,当每队的第一个棋子开始移动后后面的棋子必须不能和它位于两个连续的位置,否则会因为不能退后这个条件而失败。而本题的最原始的题目其实条件是可以跳过一个棋子进入空格。
3)算法设计:棋子移动时主要担心的问题就是会不会堵塞,
当棋子移动一步之前需要考虑下一步会不会堵塞,比如0010_11,如果走白子就是001_011但下面就没法走了,因为如果你移动黑子00110_1,黑子有两个在一起了,造成了堵塞,导致00无法前进,而如果走白子0_10011,白子又有两个在一起了,又造成了堵塞,导致黑子无法正常前进了,因此本题考虑的其实是如何不堵塞。
4)找规律:解题时如果能够事先找到题目的规律就可以事半功倍了,本题可以依靠“_”作为参考点,通过“_”左右点的不断变化来确定下一步该如何去走。按左右点的变化大致先分为 1_0 ,0_1,1_1,0_0,特殊的如当“_”到了数组的边界时_?????? 或??????_需要额外讨论,防止数组单元溢出。
当为0_1时,需要通过_index>4或者_index<4来判断(_index是“_”在数组中所在单元下标的位置),这么理解:0_1时0是往右移动的,1是往左移动的,当“_”在数组的右半部时,0左边一定不可能是0(00_1,白子一定是不能连在一起的,除非最右边已经有白子了。如??010_0)。
因此0左边会是为1,而1是往左边前进的不能后退。所以,当_index>3时只能“_”先将右边的1往左边移动(你可能会想为什么不将0往右边移动呢?已经知道是???10_1 ,如果左移0那么下一步???1_01只能将0右边的1左移,就会产生两个连续的1造成堵塞了)。同理,当_index<3时是先移动左边的0的。
当为1_0时,“_”左边的1是往左边移动的,而右边的0是往右边移动的,因此要看的其实就是1左边是什么,0右边是什么,我们通过_index>3和_index<3可以判断,当在数组右半部时,最好判读1左边,为什么?首先是为了防止数组下标越界,其次已经在右边部分了,而且0已经到1的右边了,说明在(数组右边部分)“_”左边的1是不可能存在11_0情况的,那么其实只有是01_0,也就是只能将0右移,
同理可得_index<3时是将0左边的1左移。
当为0_0或1_1时,这里0_0时,只有判断右边有没有1(不需要判断左边是否有0,第一有0先动的时第一个0,不能跳过本队的棋子),如果有1就将1左移,如果没有1(其实就是????0_00或者就是????0_0)直接将左边的0右移。同理对于1_1,左边有0就将0右移,没有就将右边的1左移。
当为数组边界时,也就是_?????? 或??????_
只有判断"_"旁边的数,如果是数组最左边,判断它右边是否有1(步数0就是1),将它右移。同理,当时数组最右边时,将它左边最靠近的0右移。
***代码展示***
#include<iostream>
using namespace std;
unsigned _index = 2;//index=3,3表示起始时"_"所在位置,000_111,这里写2就是先让0先移动,00_0111;
void show(char *Array) {//用于显示数组
for (int i = 0; i<(7); i++)
cout << Array[i];
cout << endl;
}
bool GameOver(char *Array)//判断游戏是否结束
{
int i = 0;
for (i = 0; i<3; i++)
{
if (*(Array + i) == '0') return false;
}
for (i = 6; i >= 4; i--)
{
if (*(Array + i) == '1') return false;
}
return true;
}
void SwapPos(char *Array, unsigned &_index) {//传引用,为了随时改变本身的参数
// _??????时
if (_index == 0)
{
while (1)//最多执行两次 _01  或者_10,
{//如果_旁边为1直接将1换位
if (Array[_index + 1] == '1') {
Array[_index] = '1';
Array[_index + 1] = '_';
_index = 1;
break;
}
else {//_01
Array[_index] = '1';
Array[_index + 2] = '_';
_index = 2;
break;
}
}
show(Array);
}
/*  ??????_时 */
if (_index == 6)
{
while (1)//最多执行两次 01_  或者10_,
{//如果_旁边为1直接将1换位
if (Array[_index - 1] == '0') {
Array[_index] = '0';
Array[_index - 1] = '_';
_index = 5;
break;
}
else {//_01
Array[_index] = '0';
Array[_index - 2] = '_';
_index = 4;
break;
}
}
show(Array);
}
//0_1情况  此时0想向右移动,而1想向左移动
if (Array[_index - 1] == '0'&&Array[_index + 1] == '1')
{
if (_index<3) {//_index小于4时0先右移
Array[_index] = '0';
Array[_index - 1] = '_';
_index--;
}
else {//_index大于3时1向左边移动
Array[_index] = '1';
Array[_index + 1] = '_';
_index++;
}
show(Array);
}
// 1_0时 只有旁边的数可能移动,而且是不可能同时出现相向的 
if (Array[_index - 1] == '1'&&Array[_index + 1] == '0')
{
if (_index<3) {//_index小于3先判断_的右边(也是为了防止越界)1_00是不可能出现的,因为小于4,还没有结束,0和0是不能在一起的
Array[_index + 2] = '_';
Array[_index] = '1';
_index = _index + 2;
}
else {//_index大于3先判断_的左边边 由上面推理得只能是01_0
Array[_index] = '0';
Array[_index - 2] = '_';
_index = _index - 2;
}
show(Array);
}
//0_0
if (Array[_index - 1] == '0'&&Array[_index + 1] == '0')//!!直接写连等‘0’不识别
{
if (Array[_index + 2] == '1') {//0_01
Array[_index] = '1';
Array[_index + 2] = '_';
_index = _index + 2;
}
else {//0_00 时,左边的0右移
Array[_index] = '0';
Array[_index - 1] = '_';
_index = _index - 1;
}
show(Array);
}
//1_1
if (Array[_index - 1] == '1'&&Array[_index + 1] == '1')
{
if (Array[_index - 2] == '0') {//01_1
Array[_index] = '0';
Array[_index - 2] = '_';
_index = _index - 2;
}
else {//11_1
Array[_index] = '1';
Array[_index + 1] = '_';
_index = _index + 1;
}
show(Array);
}
}
int main() {
/*数组初始化*/
char Array[7] = { '0','0','_','0','1','1','1' };
/*用于显示初始化的数组*/
show(Array);
/*移动棋子*/
while (!GameOver(Array)) {
SwapPos(Array, _index);
}
return 0;
}




***运行结果:***
00_0111
0010_11
00101_1
001_101
0_10101
_010101
10_0101
1010_01
101010_
10101_0
101_100
1_10100
11_0100
1110_00
111_000
请按任意键继续. . .