zoukankan      html  css  js  c++  java
  • 【例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("
    ");
    	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;
    }
    

      

  • 相关阅读:
    linux 短信收发
    sama5d3 环境检测 adc测试
    【Codeforces 723C】Polycarp at the Radio 贪心
    【Codeforces 723B】Text Document Analysis 模拟
    【USACO 2.2】Preface Numbering (找规律)
    【Codeforces 722C】Destroying Array (数据结构、set)
    【USACO 2.1】Hamming Codes
    【USACO 2.1】Healthy Holsteins
    【USACO 2.1】Sorting A Three-Valued Sequence
    【USACO 2.1】Ordered Fractions
  • 原文地址:https://www.cnblogs.com/DarkValkyrie/p/10387968.html
Copyright © 2011-2022 走看看