UVa 10795

题目大意:给出n,表示说有n个大小不同的盘子,然后再给出每个盘子的初始位置和目标位置,要求计算出最少的步数使得每个盘子都移动到它的目标位置。

分析:  首先找最大不在目标柱子上的盘子K,因为如果最大的盘子在目标柱子上它不需要移动,也不碍事。

因此问题就成了把K移动到目标柱子,把1到(k-1)移动到中转柱子,所以假设K从A移动到B,A只有K,B是空的,C上面是K-1到1,把这个局面称为参考局面。因为移动是对称的,所以从参考局面移到目标局面与目标局面移到参考局面是一样的步数。

所以问题变成答案=从初始局面移到参考局面步数+目标局面移到参考局面步数+1;

需要写一个函数f(P,i,final),表示已知个盘子的初始柱面编号数组为P,把1到i移动到final的步数,本题答案是f(start,k-1,6-start[k]-finish[k])+f(finish,k-1,6-start[k]-finish[k])+1;

计算f(P,i,final),若p[i]=final,则f(P,i,final)=f(P,i-1,final);否则需要把前i-1个盘子挪到中转盘去,将盘子i移到柱子final去,做后把前i-1个盘子从中转盘移到柱子final.。最后一步是把i-1个盘子从一个柱子移到另一个柱子,根据旧汉诺塔问题,这个步骤需要2^(i-1)-1步,加上移动盘子i那一步,一共需要2^(i-1)步。

f(P,i,final)=f(P,i-1,6-p[i]-final)+2^(i-1);

#include <iostream>
#include <cstdio>
#include <cstring>
#define MAXN 100
#define LL long long
using namespace std;
int st[MAXN],ed[MAXN];
LL fun(int *p,int i,int final)
{
if(i==0)return 0;
if(p[i]==final)return fun(p,i-1,final);
return fun(p,i-1,6-final-p[i])+(1LL<<(i-1));
}
int main()
{
int n;
int cas=1;
while(~scanf("%d",&n)&&n)
{
for(int i=1; i<=n; i++)
scanf("%d",&st[i]);
for(int i=1; i<=n; i++)
scanf("%d",&ed[i]);
int k=n;
while(st[k]==ed[k]&&k)k--;
LL ans=0;
if(k!=0)
{
int tem=6-st[k]-ed[k];
ans=fun(st,k-1,tem)+fun(ed,k-1,tem)+1;
}
printf("Case %d: %lld ",cas++,ans);
}
return 0;
}

原文地址:https://www.cnblogs.com/tsw123/p/4324198.html