【例7.6】黑白棋子的移動


1327:【例7.6】黑白棋子的移動


時間限制: 1000 ms         內存限制: 65536 KB
提交數: 1475     通過數: 617 

【題目描述】

有2n個棋子(n≥4)排成一行,開始位置為白子全部在左邊,黑子全部在右邊,如下圖為n=5的情形:

○○○○○●●●●●

移動棋子的規則是:每次必須同時移動相鄰的兩個棋子,顏色不限,可以左移也可以右移到空位上去,但不能調換兩個棋子的左右位置。每次移動必須跳過若干個棋子(不能平移),要求最后能移成黑白相間的一行棋子。如n=5時,成為:

○●○●○●○●○●

任務:編程打印出移動過程。

 

【輸入】

輸入n。

【輸出】

移動過程。

【輸入樣例】

7

【輸出樣例】

step 0:ooooooo*******--
step 1:oooooo--******o*
step 2:oooooo******--o*
step 3:ooooo--*****o*o*
step 4:ooooo*****--o*o*
step 5:oooo--****o*o*o*
step 6:oooo****--o*o*o*
step 7:ooo--***o*o*o*o*
step 8:ooo*o**--*o*o*o*
step 9:o--*o**oo*o*o*o*
step10:o*o*o*--o*o*o*o*
step11:--o*o*o*o*o*o*o*

例題不怎么詳的解:
經過對題目的觀察,發現題目規律,當n>4時,總是將中間的一對兩個不同的棋子移到最右邊的空位,然后再把最左邊的黑棋子移到中間,如此往復,直到剩下四對黑白棋沒有移動。
不過我們發現,這4對棋子的移法是一成不變的,不受其他棋子影響。
因此,這個條件就可以作為遞歸邊界,得出最后5步的走法。
看輸出樣例,可以得到剩下4步的普適移法,即:
  1. 先將第4、5個棋子移到右邊空位。
  2. 將第8、9位置的棋子移到先前的空位。
  3. 將2、3位置的棋子移到先前的空位。
  4. 將7、8位置的棋子移到先前的空位。
  5. 將5、6位置的棋子移到之前的空位。

驚訝的發現,每次移動都是將某對棋子移到兩個空位上,那么n>4時呢?

同樣的,也是將中間的一對移到空位上,再將最右邊的一對黑棋移到先前的空位上,如此往復。

恍然大悟。

算法分析:

本題的關鍵點就在於這個空位的問題,抓住了這個點,本題也就迎刃而解,因此我們需要設置一個代表空位起始位置的變量sp。

另一個要點,也是代碼核心組成部分,就是移動棋子這一塊了,通過上面的分析,我們得出普適的兩步:

  1. 把中間位置的一對黑白棋移到最右邊。
  2. 把最左邊的一對黑棋移到中間的空位上。

這就是分治的思想,將這個問題分解成了一個個子問題,這些問題就是要進行上面兩步求解。

得出核心代碼塊:

for(j=0;j<2;j++)
	{
		a[sp+j]=a[k+j-1];
		a[k+j-1]='-';
	}
	sp=k-1;

 

接着把前面提到的n=4時的情況寫出:

if(n==4)
	{
		move(4);move(8);move(2);move(7);move(1);
	}

  

還有n>4的情況:

move(n);move(n*2-1);mv(n-1);

  

樣例代碼:

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
char a[101];
int sp,step=0,n;
void print()//輸出
{
	printf("step%2d:",step);
	for(int i=0;i<2*n+2;i++) printf("%c",a[i]);
	printf("\n");
	step++;
}
void move(int k)//分治:移動
{
	int j;
	for(j=0;j<2;j++)
	{
		a[sp+j]=a[k+j-1];
		a[k+j-1]='-';
	}
	sp=k-1;
	print();
}
void mv(int n)//遞歸求解
{
	int i,k;
	if(n==4)
	{
		move(4);move(8);move(2);move(7);move(1);
	}
	else
	{
		move(n);move(n*2-1);mv(n-1);
	}
}
int main()
{
	int i;
	scanf("%d",&n);
	for(i=0;i<n;i++) a[i]='o';
	for(i=n;i<2*n;i++) a[i]='*';
	a[2*n]='-';a[2*n+1]='-';
	sp=2*n;//初始化
	print();
	mv(n);
	return 0;
}

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM