目前做过的最纠结的一道递推题。
情况比较多,比较复杂。。。
这题最主要的还是要推出当m=2 时和m>2时,用什么方法最优。
给个数据
n=3,m=2 需要48
n=3,m=3 需要81
如果在纸上把这两种情况推出来,这题就容易找到递推。
m=1,就是最基础的汉诺塔递推了。
很O_O的汉诺塔
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 561 Accepted Submission(s): 67
Problem Description
O_O汉诺塔包含n种不同大小盘,每种大小m个; 要求每次仅移动一个盘,不允许一个较大的盘放在较小盘上。 并且要求最后排列所有相等大小盘按原来从上到下次序,并且只能按规定的方向搬运,如图(比如A直接搬运到C是不允许的!). 求已知n,m的情况下 从A搬运到C所有盘所用的最少次数。
Input
每行输入n和m两个整数 0<n<1000,0<m<100;
Output
每行输出对应解,为避免高精度将结果对20090308取模.
Sample Input
1 3 2 4
Sample Output
6 28
Source
// // main.cpp // hdu2587 // // Created by 陈加寿 on 16/3/17. // Copyright © 2016年 chenhuan001. All rights reserved. // #include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define N 1100 #define MOD 20090308 long long dp[N][2]; //来一个统计,每个小块被搬多少次 long long save[N][N][2]; long long m; int tn; int g[N]; long long dfs(int n,int flag) { if(dp[n][flag]!=-1) return dp[n][flag]; if(flag == 1) { dp[n][flag] = (2*dfs(n-1,1)+2*m+dfs(n-1,0))%MOD; save[n][n][flag]=2; if(n== tn) { for(int i=1;i<=n-1;i++) { save[n][i][flag]+=save[n-1][i][1]+save[n-1][i][0]; save[n][i][flag]%=2; } } else { for(int i=1;i<=n-1;i++) { save[n][i][flag]+=2*save[n-1][i][1]+save[n-1][i][0]; save[n][i][flag]%=2; } } } else { dp[n][flag] = (2*dfs(n-1,1)+m)%MOD; save[n][n][flag] = 1; for(int i=1;i<=n-1;i++) { save[n][i][flag] += 2*save[n-1][i][1]; save[n][i][flag]%=2; } } return dp[n][flag]; } int main() { int n; while(cin>>n>>m) { tn = n; //来测试一种方法。! memset(save,0,sizeof(save)); memset(g,0,sizeof(g)); memset(dp,-1,sizeof(dp)); dp[1][0] = m; save[1][1][0] = 1; dp[1][1] = 2*m; save[1][1][1] = 2; dfs(n,1); //对于n if(m>2) { if(n<=2) { cout<<dp[n][1]<<endl; } else { cout<<(dp[n][1]+2*(dp[n-2][1]+dp[n-2][0]))%MOD<<endl;//进行一次调整。 } } else if(m==2) { //m == 2时 if(n<=2) { cout<<dp[n][1]<<endl; } else { //int cnt=1; //cout<<(dp[n][1]+2*(dp[n-2][1]+dp[n-2][0])-3*m*(n-2) )%MOD<<endl;//进行一次调整。 //各种不对。 long long tans=0; for(int i=n;i>1;i--) { //把第i个块,从A放入C中 //第一步判断是否需要调整 if(g[i] == 1) { tans = (tans + dp[i-1][0] + dp[i-1][1])%MOD;//调整 for(int j=1;j<i;j++) { g[j] += save[i-1][j][0]+save[i-1][j][1]; g[j]%=2; } } tans = (tans + dp[i-1][0] + dp[i-1][1]+2*m)%MOD; for(int j=1;j<i;j++) { g[j] += save[i-1][j][0]+save[i-1][j][1]; g[j]%=2; } } cout<<(tans+4)%MOD<<endl;//这样既然是对的,那么上面也是对的 } } else// m == 1 { cout<<dp[n][1]<<endl; } // for(int i=1;i<=n-2;i++) // save[n][i][1] += 2*save[n-2][i][0]+2*save[n-2][i][1]; // // for(int i=1;i<=n;i++) // cout<<i<<" "<<save[n][i][1]<<endl; } return 0; }