题目分析:将当前层定义为第h层,共用了n块积木,本层积木数为m,f(h,n,m)
那么可以扩展数两种状态:f(h-1,n-m,m-1),f(h-1,n-m,m+1)
直接搜索可能的数据达到h^m,超时超空间。
通过记录中间状态减少重复计算,同时剪枝:所有n个积木搭h层,每层积木平均数1<x<10, 超过这个范围就不可能了。
搜索的边界条件也要考虑到。F(1,i,i)=1.
动态规划的方程也可以写出来:f(h,n,m)=f(h-1,n-m,m-1)+f(h-1,n-m,m+1)
递归找方案:查找第k个方案的时候,根据节点左右关系,比左节点小向左找,否则向右找
注意向右找时k要减掉左侧的方案数
代码:
#include<iostream> using namespace std; int N,H,M; long long k; long long f[65][550][15]; bool vis[65][550][15]; long long dfs(int h,int n,int m){ if(m>10||m<1)return 0; if(n/h>10||n/h<1)return f[h][n][m]=0;//剪枝 if(vis[h][n][m])return f[h][n][m]; if(h==1){ vis[h][n][m]=true; if(m==n)return f[h][n][m]=1; else return f[h][n][m]=0; } f[h][n][m]=0; if(n-m>0){ f[h][n][m]+=dfs(h-1,n-m,m+1); f[h][n][m]+=dfs(h-1,n-m,m-1); } vis[h][n][m]=true; return f[h][n][m]; } void find(long long x,int h,int n,int m){ cout<<m<<' '; if(h>=2){ if(x<=f[h-1][n-m][m-1])find(x,h-1,n-m,m-1); else find(x-f[h-1][n-m][m-1],h-1,n-m,m+1); } } int main(){ cin>>N>>H>>M; cout<<dfs(H,N,M)<<endl; while(1){ cin>>k; if(k<0)break; else find(k,H,N,M); cout<<endl; } return 0; }
测试点#0.in 结果:AC 内存使用量: 1128kB 时间使用量: 0ms
测试点#1.in 结果:AC 内存使用量: 256kB 时间使用量: 1ms
测试点#2.in 结果:AC 内存使用量: 364kB 时间使用量: 1ms
测试点#3.in 结果:AC 内存使用量: 492kB 时间使用量: 0ms
测试点#4.in 结果:AC 内存使用量: 360kB 时间使用量: 0ms
测试点#5.in 结果:AC 内存使用量: 364kB 时间使用量: 0ms
测试点#6.in 结果:AC 内存使用量: 488kB 时间使用量: 0ms
测试点#7.in 结果:AC 内存使用量: 1004kB 时间使用量: 0ms
测试点#8.in 结果:AC 内存使用量: 492kB 时间使用量: 0ms
测试点#9.in 结果:AC 内存使用量: 748kB 时间使用量: 0ms