zoukankan      html  css  js  c++  java
  • Uva 10795 A Different Task

    汉诺塔问题的变形,给定初始局面和目标局面,问最少多少步可以把初始局面变成目标局面。

    找到初始位置和目标位置不同的最大盘子X,那么比这个盘子还大的盘子就可以无视掉了。因为他们既不会被移动也不需要被移动。

    我们设f(p[],x,final)为当前初始状态为p,要把比x小的盘子移动到柱子final的最少步数那么有f(p[],x,final)=f(p[],x-1,6-final-p[x])+2^(x-1)-1+1

    意思就是先把比x-1小的都移动到柱子6-final-p[x],然后把x-1移动到final,然后把比x-1小的盘子移动到final

    有了这个式子之后,我们要求的答案可以分解成,从开始局面开始,把比X小的盘子全部移动到中转位置,然后移动X,然后在移动到目标局面即可。最后移动到目标局面可以看成是从目标局面移动到中转位置,那么答案就是

    ans=f(start[],X,6 – start[X] – final[X]) + f(final[],X,6 – start[X] – final[X]) + 1

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    
    using namespace std;
    
    typedef long long LL;
    const int maxn = 70;
    int start[maxn],finish[maxn];
    
    LL f(int P[],int i,int fin) {
    	if(i == 0) return 0;
    	if(P[i] == fin) return f(P,i - 1,fin);
    	return f(P,i - 1,6 - P[i] - fin) + 1 + (1LL << (i - 1)) - 1;
    }
    
    int main() {
    	int n,kase = 1;
    	while(scanf("%d",&n),n) {
    		LL ans = 0LL;
    		for(int i = 1;i <= n;i++) {
    			scanf("%d",&start[i]);
    		}
    		for(int i = 1;i <= n;i++) {
    			scanf("%d",&finish[i]);
    		}
    		for(int i = n;i >= 1;i--) if(start[i] != finish[i]) {
    			ans = f(start,i - 1,6 - start[i] - finish[i]) + f(finish,i - 1,6 - start[i] - finish[i]) + 1;
    			break;
    		}
    		cout << "Case " << kase << ": " << ans << endl;
    		kase++;
    	}
    	return 0;
    }

    总结:汉诺塔类问题关键就是要找到一个会重叠出现的状态,然后写出递归式求解,中间也可以利用一些数学结论和技巧,比如可逆性。

  • 相关阅读:
    WHAT I WANT TO DO ?
    BACK找工作感悟
    C++基础六-结构体
    C++基础五-指针
    C++基础四-函数
    C++基础三-数组

    C++基础三-循环控制
    C++基础二-条件判断
    PHP 基础
  • 原文地址:https://www.cnblogs.com/rolight/p/3541396.html
Copyright © 2011-2022 走看看