移棋问题 C语言版

前言

最近一直逛论坛,回答了不少题,额,但是回复比较少(可能急需或者根本就不怎么在乎),感觉有点浪费,所以我打算整理一下,写几篇博文,好让小伙伴们第一时间找到。

问题

先说第一个问题:
有2n个棋子(n≥4)排成一行,开始位置为白色全部在左边,黑色全部在右边。移动棋子的规则是:每次必须同时移动相邻两个棋子,颜色不限,可以左移也可以右移一空位上去,但不能调换两个棋子的左右位……每次移动必须跳过若干个棋子(不能平移),要求最后能够移成黑白相间的一行棋子。
然后还告诉你当n=4的时候是怎么移动的(找不到原问题了,原问题是坐标移动,但是有点不够具体)
ooooxxxx__
ooo__xxxox
oooxoxx__x
o__xoxxoox
oxoxox__ox
__oxoxoxox

浅析问题

文字终究没有图像好,所以我打算画一个图(画风有点差,用软件有点麻烦),所以就用代码示意。
o:表示白棋
x:表示黑棋
_:表示空位

1.初始
先举5的例子(这里也是为什么n>=4的原因,因为其他都是建立在4 的基础之上,然后抽化思维,运用递归实现
oooooxxxxx__这是刚开始的图像,也是有2n个棋子(n≥4)排成一行,开始位置为白色全部在左边,黑色全部在右边的解释。

oooo__xxxxox,这是将ox看成一组进行移动,确保交替出现,也是核心操作之一。

ooooxxxx__ox,看到这里发现前面10个是不是有点眼熟?其实就是n=4的时候的棋子,而且后面两个还是交替的,也就将5的问题转换成求4的问题了。

2.小结
建立与4的基础上,将n>4时,进行不断的转换成求n-1的问题,直到转换成求n=4的问题,从而达到目的。
数学模型
主要是核心步骤的数学模型,即问题的不断转换的两个的数学模型
注意这里的棋子坐标从1开始算起,主要是方便计算)
oooooxxxxx__---->oooo__xxxxox,当n=k(n>4)时,先将k和k+1移动到2k+1,2k+2坐标
oooo__xxxxox—>ooooxxxx__ox,然后将其k减下,k和k+1移动到2k-1,2k从而将问题转化成只需要变前面的10个坐标。

代码实现

代码分析看注释

#include<stdio.h>
char a[100];
char b[2];//也可以用两个全局变量
void pr(int k)//打印棋盘图像,k为白棋或者黑棋数目
{
	int i;
	for(i=1;i<=2*k+2;i++)//从1开始,为了方便计算,也可以从0开始
	{
		printf("%c",a[i]);
	}
	printf("\n");
}
void move(int k,int n)
{
	if(k==4)//打印n=4的时候图像的变化
	{
		//printf("4,5-->9,10\n");这是打印坐标的变化
		b[0]=a[9];b[1]=a[10];
		a[9]=a[4];a[10]=a[5];
		a[4]=b[0];a[5]=b[1];
		pr(n);
		//printf("8,9-->4,5\n");
		b[0]=a[4];b[1]=a[5];
		a[4]=a[8];a[5]=a[9];
		a[8]=b[0];a[9]=b[1];
		pr(n);
		//printf("2,3-->8,9\n");
		b[0]=a[8];b[1]=a[9];
		a[8]=a[2];a[9]=a[3];
		a[2]=b[0];a[3]=b[1];
		pr(n);
		//printf("7,8-->2,3\n");
		b[0]=a[2];b[1]=a[3];
		a[2]=a[7];a[3]=a[8];
		a[7]=b[0];a[8]=b[1];
		pr(n);
		//printf("1,2-->7,8\n");
		b[0]=a[7];b[1]=a[8];
		a[7]=a[1];a[8]=a[2];
		a[1]=b[0];a[2]=b[1];
		pr(n);
	}
	else
	{
		//printf("%d,%d-->%d,%d\n",k,k+1,2*k+1,2*k+2);
		b[0]=a[2*k+1];b[1]=a[2*k+2];
		a[2*k+1]=a[k];a[2*k+2]=a[k+1];
		a[k]=b[0];a[k+1]=b[1];
		pr(n);//完成了核心步骤1
		//printf("%d,%d-->%d,%d\n",2*k-1,2*k,k,k+1);
		b[0]=a[k];b[1]=a[k+1];
		a[k]=a[2*k-1];a[k+1]=a[2*k];
		a[k*2-1]=b[0];a[2*k]=b[1];
		pr(n);//完成核心步骤2
		move(k-1,n);//将问题转换成求k-1
	}
	

}

int main()
{
	int N,i,j;
	scanf("%d",&N);//输入有多少白棋或者黑棋
	while(N<4)//当输入小于4时,视为无效输入,等待继续输入
	{
		scanf("%d",&N);
	}
	for(i=0;i<100;i++)//默认刚开始棋盘没有棋子
	{
		a[i]='_';
	}
	for(i=1;i<=N;i++)//添加白棋
	{
		a[i]='o';
	}
	for(i=N+1;i<=2*N;i++)//添加黑棋
	{
		a[i]='x';
	}
	pr(N);//打印初始排布
	move(N,N);//移动棋子
	return 0;
}

结果图

编辑环境:sources insight
运行环境:gcc
在这里插入图片描述
如果需要坐标的方式也可以,注释掉的代码就是坐标移动,将其取消注释,然后稍微改一下就可以了,实现图
在这里插入图片描述

结语

士不可以不弘毅,任重而道远。
如果有什么疑问或者其他,可以私信或者留言。

猜你喜欢

转载自blog.csdn.net/qq_44885018/article/details/103604315