哈诺塔基本算法:
将A上的n-1个借助C移到B,再将第n个盘子移到C,最后将B上的n-1个盘子借助A移到C。
得出的规律性结论:把n个盘子从A移到C的次数是2的n次方-1
#include<bits/stdc++.h>
using namespace std;
int cnt=0;
int a=1,b=2,c=3;
int f(int n,int a,int c,int b){
if(n==1) {
++cnt;
printf("%d %d %d\n",n,a,c);
return cnt;
}
f(n-1,a,b,c);
printf("%d %d %d\n",n,a,c);
++cnt;
f(n-1,b,c,a);
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
cnt=0;
f(n,a,c,b);
printf("cnt==%d\n",cnt);
//把n个从A移到C的次数是2的n次方-1
}
return 0;
}
uva10795:
给定了初始和最终状态,求移动次数,并且规定盘子大小的次序始终是从小到大
首先判断移动第k个盘子时:先将k-1个移动到非目标方,然后把k移动到目标方,移动k-1个盘子的次数是2的k-1次方
然后:定义参考局面,就是移动k-1后的状态
最后:根据移动可逆,所求次数就是初始状态移到参考局面+最终状态移到参考局面+最后移动的第个k盘子
#include<bits/stdc++.h>
using namespace std;
int start[65];
int Final[65];
long long f(int *start,int k,int Final_)
{
if(k==0) return 0;
if(start[k]==Final_) return f(start,k-1,Final_);
else return f(start,k-1,6-Final_-start[k])+(1LL<<(k-1));
}
int main()
{
int n,kase=1;
while(~scanf("%d",&n)&&n){
long long ans=0;
for(int i=1;i<=n;i++) scanf("%d",&start[i]);
for(int i=1;i<=n;i++) scanf("%d",&Final[i]);
int k=n;
while(k>=1&&start[k]==Final[k]) k--;
if(k>=1){
ans = f(start,k-1,6-Final[k]-start[k])+f(Final,k-1,6-Final[k]-start[k])+1;
}
printf("Case %d: %lld\n",kase++,ans);
}
return 0;
}
URAL 2029
此题就是上一个题的变形,初始状态在题意里已经给出。
#include<bits/stdc++.h>
using namespace std;
char start[65];
char Final[65];
long long f(char *start,int k,char Final_)
{
if(k==0) return 0;
if(start[k]==Final_) return f(start,k-1,Final_);
else return f(start,k-1,'A'+'B'+'C'-Final_-start[k])+(1LL<<(k-1));
}
int main()
{
int n,kase=1;
scanf("%d",&n);
long long ans=0;
for(int i=1;i<=n;i++) start[i]='A'; getchar();
for(int i=1;i<=n;i++) scanf("%c",&Final[i]);
int k=n;
while(k>=1&&start[k]==Final[k]) k--;
if(k>=1){
ans = f(start,k-1,'A'+'B'+'C'-Final[k]-start[k])+f(Final,k-1,'A'+'B'+'C'-Final[k]-start[k])+1;
}
printf("%lld",ans);
return 0;
}