由此产生了许多有趣的问题,而这些问题往往和递归递推有关。本文的问题均来自杭电。
hdu 1207 汉诺塔II
http://acm.hdu.edu.cn/showproblem.php?pid=1207
同I的变化:现在多了一根柱子,一共有4根柱子。
分析:在汉诺塔I的基础上有了第四根柱子后,每一步都需找到最小的移动次数,不是简单的
#include <iostream>
#include <cstdio>
using namespace std;
typedef unsigned long long ull;
ull f[70];
const ull one=1;
int main()
{
int n;
f[1]=1;
f[2]=3;
for(int i=3;i<=64;i++){
ull minm=2*f[1]+(one<<(i-1))-1;
for(int j=2;j<i;j++){
ull temp=2*f[j]+(one<<(i-j))-1;
if(minm>temp) minm=temp;
}
f[i]=minm;
}
while(cin>>n){
printf("%llu\n",f[n]);
}
return 0;
}
hdu 2064 汉诺塔III
http://acm.hdu.edu.cn/showproblem.php?pid=2064
同I的变化:不允许直接从最左(右)边移到最右(左)边(每次移动一定是移到中间杆或从中间移出)
于是得到递推式:
import java.util.*;
public class Main {
static long []h=new long [40];
public static void main(String[] args) {
h[1]=2;
for(int i=2;i<=35;i++){
h[i]=3*h[i-1]+2;
}
int n;
Scanner sc=new Scanner (System.in);
while(sc.hasNext()){
n=sc.nextInt();
System.out.println(h[n]);
}
}
}
hdu 2077 汉诺塔IV
http://acm.hdu.edu.cn/showproblem.php?pid=2077
同I比较:允许最大的盘子放到最上面会怎么样呢?(只允许最大的放在最上面)当然最后需要的结果是盘子从小到大排在最右边。
import java.util.*;
public class Main {
static long [] h=new long [25];
static long []f=new long [25];
public static void main(String[] args) {
Scanner sc=new Scanner (System.in);
h[1]=1;
for(int i=2;i<=20;i++){
h[i]=3*h[i-1]+1;
}
f[1]=2;
f[2]=4;
for(int i=3;i<=20;i++){
f[i]=2+2*h[i-1];
}
int n,t;
t=sc.nextInt();
while(t>0){
n=sc.nextInt();
System.out.println(f[n]);
t--;
}
}
}
hdu 1995 汉诺塔V
http://acm.hdu.edu.cn/showproblem.php?pid=1995
同汉诺塔I的变化: 告之盘子总数和盘号,计算该盘子的移动次数.
分析:背景是最原始的汉诺塔,h(n)=2h(n-1)+1 h(1)=1 进一步得到:.依次对应的是n盘,n-1盘,n-2盘……1盘
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner (System.in);
long t,n,i;
t=sc.nextLong();
while(t>0){
n=sc.nextLong();
i=sc.nextLong();
long ans=(long)1<<(n-i);
System.out.println(ans);
t--;
}
}
}
hdu 1996 汉诺塔VI
http://acm.hdu.edu.cn/showproblem.php?pid=1996
n个盘子的汉诺塔问题的最少移动次数是2^n-1,即在移动过程中会产生2^n个系列。由于
发生错移产生的系列就增加了,这种错误是放错了柱子,并不会把大盘放到小盘上,即各柱
子从下往上的大小仍保持如下关系 :
n=m+p+q
a1>a2>...>am
b1>b2>...>bp
c1>c2>...>cq
计算所有会产生的系列总数.
分析:第n个盘子先放,有3种选择;第n-1个盘子再放,也有3种选择……第1个盘子放有3种选择。所以一共有3^n种结果。
import java.util.*;
public class Main {
static long []f=new long [35];
public static void main(String[] args) {
f[1]=3;
for(int i=2;i<=30;i++){
f[i]=f[i-1]*3;
}
Scanner sc=new Scanner (System.in);
int n,t;
t=sc.nextInt();
while(t>0){
n=sc.nextInt();
t--;
System.out.println(f[n]);
}
}
}
hdu 1997 汉诺塔VII
http://acm.hdu.edu.cn/showproblem.php?pid=1997
n个盘子的汉诺塔问题的最少移动次数是2^n-1,即在移动过程中会产生2^n个系列。由于发生错移产生的系列就增加了,这种错误是放错了柱子,并不会把大盘放到小盘上,即各柱子从下往上的大小仍保持如下关系 :
n=m+p+q
a1>a2>...>am
b1>b2>...>bp
c1>c2>...>cq
ai是A柱上的盘的盘号系列,bi是B柱上的盘的盘号系列, ci是C柱上的盘的盘号系列,最初目标是将A柱上的n个盘子移到C盘. 给出1个系列,判断它是否是在正确的移动中产生的系列.
例1:n=3
3
2
1
是正确的
例2:n=3
3
1
2
是不正确的。
注:对于例2如果目标是将A柱上的n个盘子移到B盘. 则是正确的.
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int m[3],map[3][70];
int judge;
void dfs(int sum,int a,int b,int c){
if(judge==0 || judge==1) return ;
if(sum==0){ judge=1; return ; }
if(map[a][m[a]]==sum){
m[a]++;
dfs(sum-1,a,c,b);
}
else if(map[c][m[c]]==sum){
m[c]++;
dfs(sum-1,b,a,c);
}
else {
judge=0;
return ;
}
}
int main()
{
//freopen("cin.txt","r",stdin);
int t,n;
cin>>t;
while(t--){
scanf("%d",&n);
memset(map,0,sizeof(map));
for(int i=0;i<3;i++){
scanf("%d",&m[i]);
for(int j=0;j<m[i];j++){
scanf("%d",&map[i][j]);
}
}
m[0]=m[1]=m[2]=0;
judge=-1;
dfs(n,0,1,2);
if(judge==1) puts("true");
else puts("false");
}
return 0;
}