目录
汉诺塔
网图:https://www.zhihu.com/question/24385418
题意:
汉诺塔是一种古老的游戏。 一共3个柱子,标号为1,2,3 1号柱子有从大到小一共n个盘子。
每次移动最上方的一个盘子,可以移动到其他的柱子。 任何一个盘子,都不能叠在比它更小的盘子的上方。 请把盘子从1号柱子,全部移动到3号柱子。
思路:
只有一个的时候: 从A—>C即可。
只有两个的时候:先将最上面从A-->B,再将最大的从A—>C,再将B的移到C。
三个的时候:先将最上面两个用上面最有两个的情况移动到B中,此时C为中转柱,B为目标柱。再将最大的也就是第三个从A—>C,再将B的两个同样方式由B出发移动到C。
(步数最小原因:若想最大的先进入C,只能让上面的两个进入B腾出位置,也就是对应两个的时候,然后再将B的两个移动到C,由此也可推出dp[i]=2*dp[i-2]+1);
……
N个的时候,先将上面的(n-1)移动B,然后再将第N个移动到C,再将B的(n-1)个移动到C。而(n-1)如何移动在上面已经递推出,也就是也N的移动方式、思维方式想用,不同的只是起始柱、中转柱、目标柱的不同。进而得到递归的核心思想:分解。把一个很复杂的问题使用同一个策略将其分解为较简单的问题,如果这个的问题仍然不能解决则再次分解,直到问题能被直接处理为止。
dfs(n,A,B,C)
下层递归dfs(n-1,A,C,B);-----此处可加语句记录路径,也就是那个移动起始柱最下面的-----------------------printf("Move %d from %c to %c\n",n,A,C);-------dfs(n-1,B,A,C);
终止条件,n==1的时候 printf("Move %d from %c to %c\n",n,A,C); return;
代码:
#include<bits/stdc++.h>
//dp[i] = dp[i-1]*2+1; dp[i-1]从1-->2 2-->1分别为dp[i-1]次 所以为2倍,然后加上最大块从1-->3;
using namespace std;
void dfs_hanoi(int n,char a,char b,char c){
if(n == 1){
printf("Move 1 from %c to %c\n",a,c);
return ;
}
dfs_hanoi(n-1,a,c,b);
printf("Move %d from %c to %c\n",n,a,c);
dfs_hanoi(n-1,b,a,c);
}
int main(){
int n;
cin >> n;
dfs_hanoi(n,'1','2','3');
return 0;
}
放苹果
思路:
分情况考虑,因为无顺序可言,对某一个盘子放与不放意义不大。对全放和至少一个不妨考虑。
dfs(m,n) 如果至少一个不放,就是dfs(m,n-1),否则就先都放上一个dfs(m-n,n);这样就转化为目前为止的n中至少一个放超过一个,
特殊情况:
n>m 肯定有n-m空盘子,因为不考虑顺序,此时=dfs(m,m);
终止条件:
n==1||m==0即只剩下一个盘子全放里面和没有剩下的苹果剩下的盘子都不放,return 1;
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdlib>
#include<map>
#include<cmath>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn = 1e6+50;
int dfs(int m,int n){
if(n==1||m==0) return 1;
if(n > m) return dfs(m,m);
return dfs(m,n-1)+dfs(m-n,n);
}
int main(){
int m,n;
int t;
cin >> t;
while(t--){
cin >> m >> n;
cout << dfs(m,n) << endl;
}
return 0;
}