zoukankan      html  css  js  c++  java
  • 新汉诺塔

    Description

    设有n(n<=50)个大小不等的中空圆盘,按从小到大的顺序从1到n编号。将这n个圆盘任意的迭套在三根立柱上,立柱的编号分别为A、B、C,这个状态称为初始状态。

    现在要求找到一种步数最少的移动方案,使得从初始状态转变为目标状态。

    移动时有如下要求:

    • 一次只能移一个盘;
    • 不允许把大盘移到小盘上面。

    Analysis

    没有头绪的一题,如果圆盘有序放置,是不是题目会简单很多?答案是肯定的。

    显而易见,每次只能移动顶层的圆盘,但是此思维类似于爆搜,是不可取的。回到汉诺塔游戏的思路,将n-1个盘子转移走,把自己放到目标杆子上,把n-1个盘子放回来,所以是一个递归的思想。

    这题规则有所改变,每个盘子都有自己的目标状态。只能把目标状态中底部的盘子先达到目标,再把另外n-1个盘子弄上去。而瞄准一个盘子怎么把它放上去呢?

    首先肯定要把目标点的盘子拾搬,把自己头上的拾搬,最后才能把自己放上去。这显然是正确的,但是拾搬的扔到哪呢?只能扔到另一根柱子上了。

    接着,我就没有彻底没有头绪了,因为任意迭套存在小的上面有大环的情况,这个拾搬的策略实在是太复杂了。先写一个初始状态一定为有序的code试试看。

    懵逼,竟然AC了。原来是我题目理解错了,放置的时候一定是有序的...

    那么这个题目就比较简单了,每次把需要移动的最大的移动过去,为了给他腾出地方,把比他小的盘子中占据目标位置和在他头上的都扔另一个杆子上去,产生子问题。

    Code

    #include <bits/stdc++.h>
    const int N=51;
    const char M[3]={'A','B','C'};
    int pole[N],tar[N],step;
    void move(int x,int s,int t){
    	if(t==s)return;
    	for(int i=x-1;i;i--)
    		if(pole[i]==t)move(i,t,3-s-t);
    		else if(pole[i]==s)move(i,s,3-s-t);
    	pole[x]=t;
    	step++;
    	printf("move %d from %c to %c
    ",x,M[s],M[t]);
    }
    int main(){
    	freopen("test.in","r",stdin);
    	freopen("test.out","w",stdout);
    	int n;
    	scanf("%d",&n);
    	for(int i=0;i<2;i++)
    		for(int j=0;j<3;j++){
    			int num,p;
    			scanf("%d",&num);
    			for(int k=1;k<=num;k++){
    				scanf("%d",&p);
    				if(!i)pole[p]=j;
    				if(i)tar[p]=j;
    			}
    		}
    	for(int i=n;i>=1;i--)
    		move(i,pole[i],tar[i]);
    	printf("%d
    ",step);
    	return 0;
    }
    
  • 相关阅读:
    Kotlin中Range与异常体系剖析
    @RequestParam与@PathVariable的区别
    thymeleaf:局部变量 th:with
    关于thymeleaf th:replace th:include th:insert 的区别
    MockHttpServletRequestBuilder中content和param的区别
    使用spring的JavaMailSender发送邮件
    Spring的注解@Qualifier小结
    MySql 中 case when then else end 的用法
    @Transient 理解
    Vue生命周期-手动挂载理解
  • 原文地址:https://www.cnblogs.com/qswx/p/9509245.html
Copyright © 2011-2022 走看看