Uva 10795 A Different Task

来源:互联网 发布:linux一键安装lnmp 编辑:程序博客网 时间:2024/04/30 17:01

1.将某一个碟子移动到一个指定柱子上,必须首先将小于它的碟子都移动到一个临时柱子上,然后将该碟子移动到指定柱子。则将第i个碟子移动到某一柱子的开销为,

  1)如果i处在目标柱子上,则开销为0,

  2)如果i不在目标柱子上,则开销为H(i-1) +1 ,H为当前状态下1---(i-1)的碟子移动到 某一柱子的开销。

 2. 下面讨论,某一状态下H的值:

   1)将同一个柱子的n个碟子已到另一个柱子上,最少移动2^(n-1) - 1次,可由f(n) = 2*f(n-1) +1推导出;

   2)将一些散乱在3个柱子上的碟子,移动到同一个柱子上。

         一.将所有n-1个碟子移动到临时柱子,开销 H(n-1)

         二.将n移动到指定柱子开销1

         三.将临时柱子上的n-1移动到指定柱子,开销2^(n-1) - 1

   由上可得,当n在指定位置时,H(n) = H(n-1),否则H(n) = H(n-1) + 2^(n-1) - 1 + 1;

  

假设给定共M个碟子,找出第一个不在指定位置的碟子N,将N-1个散乱的碟子移动到一个临时柱子,N移动到指定位置,开销H(n-1) +1;

接下来所有碟子处在同一个柱子上,H(n) =  n处在目标位置? 0:f(n-1) + 1;

 

注:临时柱子一定是,目标柱子和所处柱子之外的第三个柱子

 

 

#include <cstdlib>#include <iostream>#include <stdio.h>using namespace std;const int MAX = 60 + 5; int dsk[MAX],tag[MAX],kase = 1;long long mov_to(int num,int peg)//把所有 <= num 的数移动到 peg 号柱子上 {    if(num == 0)return 0;    if(dsk[num] == peg)return mov_to(num - 1, peg);    return mov_to(num - 1, 6 - peg - dsk[num]) + (1LL << (num - 1)); }long long caculate(int n){        long long sum = 0;    for(; n > 0 && dsk[n] == tag[n]; n--);//找出最大的 未处于目标位置的 碟子         if(n == 0)return 0;     sum += mov_to(n - 1, 6 - dsk[n] - tag[n]) + 1;        int cur = 6 - dsk[n] - tag[n];//当前 所有小于n 的碟子所在的位置     for(int i = n - 1; i > 0; i--)    {        if(tag[i] == cur)continue;                cur = 6 - cur - tag[i];        sum += (1LL << (i - 1));//所有 i-1个数 移到 临时位置的 移动次数  + 1            }        return sum;     }int main(int argc, char *argv[]){    int n;    while(scanf("%d",&n) != -1 && n)    {        for(int i = 1; i <= n; i++)scanf("%d",&dsk[i]);        for(int i = 1; i <= n; i++)scanf("%d",&tag[i]);        printf("Case %d: %lld\n",kase++,caculate(n));        }        //system("PAUSE");    return EXIT_SUCCESS;}


 

0 0