现在的位置: 首页 > 综合 > 正文

UVA – 10795(新汉诺塔问题)

2018年03月17日 ⁄ 综合 ⁄ 共 963字 ⁄ 字号 评论关闭

要从初始状态移动到目标状态,需要建立参考状态,然后根据移动的可逆性,只需将两个状态移动到参考状态的和加起来即可;

首先,最大编号在两个状态中位置相同,则没必要移动,移动反而不够成最优解,若最优解中需移动该盘子,那么在最优解中去掉该盘子来回移动的两部依然构成解,与最优解的性质矛盾;所以只需找最大的那个不同位置的盘子,才是必须需要移动的,记为k

假设将k从1移动到2,那么必须将前k-1个盘子移动到3,然后将它移动到2,该状态即参考状态;

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <map>
using namespace std;
typedef long long LL;

const int maxn = 61;
LL mi[maxn];
int n,start[maxn],finish[maxn];
LL f(int* p,int i,int final){
  if(i==0) return 0;
  if(p[i]==final){
     return f(p,i-1,final);
  }
  else {
     return f(p,i-1,6-final-p[i])+mi[i-1];
  }
}
int main()
{
    int kase=1;
    mi[0] = 1;
    for(int i=1;i<=60;i++) mi[i]=mi[i-1]*2;
    while(scanf("%d",&n)==1 && n){
      for(int i=1;i<=n;i++)
        scanf("%d",&start[i]);
      for(int i=1;i<=n;i++)
        scanf("%d",&finish[i]);
      int k=-1;
      for(int i=n;i>=1;i--){
        if(start[i]!=finish[i]){
             k = i; break;
        }
      }
      if(k==-1){
        printf("Case %d: 0\n",kase++); continue;
      }
      LL res = f(start,k-1,6-start[k]-finish[k]);
      res+=f(finish,k-1,6-start[k]-finish[k])+1;
      printf("Case %d: %lld\n",kase++,res);
    }
    return 0;
}

抱歉!评论已关闭.