ural 1148 记忆化搜索

题意:
一个堆塔游戏.这些塔是由立方体构成的.塔的高度为H(H层),塔的底部有M个立方体,上面的每层的立方体数与下一层立方体数的差为1. 现在的问题就是一共有多少个由n个立方体堆成的不同的塔,还有字典序第k大的方案.如果两个塔有一层以上的立方体数不同则两个塔就不同.

此处用记忆化搜索进行求解~~~从底往上搜索~~
根据题目开一个数组进行记录答案:long long dp[32767][61][71];
DP[n][h][m]:=还有n块积木,还剩下h层没搭建、现在搭建的当前层要放m块积木得到的总方案数~~~
对于当前状态(n,h,m)
1、可以根据h、m计算出当前状态至少需要多少积木(minn)、最多需要多少积木(maxn)
    a、如果n<minn   不够搭建,直接返回0                          
    b、如果n>maxn,实际上(n,h,m)、(maxn,h,m)这两个状态是一样的,所以将n=maxn,避免等同状态的重复存储MEL重复计算TLE
         由于maxn最多是2400,所以dp只需要开到dp[2400][61][71]即可~~
2、如果n>=maxn,且h<=m  此时爱减1加1随便,所以有两个选择,即  返回2^(h-1)即可

但是这里开long long dp[2400][61][71] 还是会MLE~~
所以这里改用map< pair<int,pair<int,int> >,long long >dp;  进行记忆化存储~~

第一次知道等同状态~~~归一等同状态可以避免重复计算避免MLE和TLE~~
同时(2)剪枝挺好的~~~以及输出第k小字典序序列的方法~~



#include <algorithm>
#include <iostream>
#include<string.h>
#include <fstream>
#include <math.h>
#include <vector>
#include <cstdio>
#include <string>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define exp 1e-8
#define fi first
#define se second
#define ll long long
#define INF 0x3f3f3f3f
#define pb(a) push_back(a)
#define mp(a,b) make_pair(a,b)
#define all(a) a.begin(),a.end()
#define mm(a,b) memset(a,b,sizeof(a));
#define for0(a,b) for(int a=0;a<=b;a++)//0---(b-1)
#define for1(a,b) for(int a=1;a<=b;a++)//1---(b)
#define rep(a,b,c) for(int a=b;a<=c;a++)//b---c
#define repp(a,b,c)for(int a=b;a>=c;a--)///
#define cnt_one(i) __builtin_popcount(i)
#define stl(c,itr) for(__typeof((c).begin()) itr=(c).begin();itr!=(c).end();itr++)
using namespace std;
void bug(string m="here"){cout<<m<<endl;}
template<typename __ll> inline void READ(__ll &m){__ll x=0,f=1;char ch=getchar();while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}m=x*f;}
template<typename __ll>inline void read(__ll &m){READ(m);}
template<typename __ll>inline void read(__ll &m,__ll &a){READ(m);READ(a);}
template<typename __ll>inline void read(__ll &m,__ll &a,__ll &b){READ(m);READ(a);READ(b);}
template<typename __ll>inline void read(__ll &m,__ll &a,__ll &b,__ll &c){READ(m);READ(a);READ(b);READ(c);}
template<typename __ll>inline void read(__ll &m,__ll &a,__ll &b,__ll &c,__ll &d){READ(m);READ(a);READ(b);READ(c);read(d);}
template < class T > inline  void out(T a){if(a<0){putchar('-');a=-a;}if(a>9)out(a/10);putchar(a%10+'0');}
template < class T > inline  void outln(T a){out(a);puts("");}
template < class T > inline  void out(T a,T b){out(a);putchar(' ');out(b);}
template < class T > inline  void outln(T a,T b){out(a);putchar(' ');outln(b);}
template < class T > inline  void out(T a,T b,T c){out(a);putchar(' ');out(b);putchar(' ');out(c);}
template < class T > inline  void outln(T a,T b,T c){out(a);putchar(' ');outln(b);putchar(' ');outln(b);}
template < class T > T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template < class T > T lcm(T a, T b) { return a / gcd(a, b) * b; }
template < class T > inline void rmin(T &a, const T &b) { if(a > b) a = b; }
template < class T > inline void rmax(T &a, const T &b) { if(a < b) a = b; }
template < class T > T pow(T a, T b) { T r = 1; while(b > 0) { if(b & 1) r = r * a; a = a * a; b /= 2; } return r; }
template < class T > T pow(T a, T b, T mod) { T r = 1; while(b > 0) { if(b & 1) r = r * a % mod; a = a * a % mod; b /= 2; } return r; }

int n,h,m;
map< pair<int,pair<int,int> >,ll>mm;
ll power[80];
int min_need(int h,int m)
{
    if(h<=m) return (m+(m-h+1))*h/2;
    return (m+1)*m/2+(h-m+1)/2*2+(h-m)/2;
}    ///h-m层
int max_need(int h,int m)
{
    return (m+(m+h-1))*h/2;
}
ll dfs(int n,int h,int m)///现在剩余的砖块、还有h层没搭建、即将用m块搭建h层
{
    if(m<=0||n<m)return 0;///剪枝
    if(n<min_need(h,m))return 0;///剪枝
    if(n>=max_need(h,m)&&h<=m)return power[h-1];///剪枝
    if(max_need(h,m)<=n)n=max_need(h,m);  ///归一等同状态、避免重复存储MLE重复计算TLE
    if(mm[mp(n,mp(h,m))]!=0) return mm[mp(n,mp(h,m))];///记忆化

    ll a=dfs(n-m,h-1,m+1);
    ll b=dfs(n-m,h-1,m-1);
    return mm[mp(n,mp(h,m))]=a+b;
}
void printf_way(ll k)
{
    int curt=m;out(curt);putchar(' ');
    int tn=n;
    ll tmp;
    for1(i,h-1)
    {
        tn-=curt;
        tmp=dfs(tn,h-i,curt-1);
        if(tmp>=k)curt--;
        else k-=tmp,curt++;
        out(curt);putchar(' ');
    }
    puts("");
}
int main()
{
    power[0]=1;
    read(n,h,m);
    for1(i,h)power[i]=power[i-1]*2LL;
    outln(dfs(n,h,m));
    ll tmp;
    while(read(tmp),tmp!=-1)
    printf_way(tmp);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值