由此产生了许多有趣的问题,而这些问题往往和递归递推有关。本文的问题均来自杭电。
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; }
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; }