codevs1255 搭积木——记忆化搜索,或者dp

本文介绍了一种基于动态规划和记忆化搜索的积木搭建算法,用于寻找满足特定条件的积木堆叠方案总数及其具体排列组合。
1255 搭积木


一种积木搭建方式,高为H的积木,最底层有M个积木,每一层的积木数是他的低一层的积木数+1或-1。总共有N个积木。(且每行积木数不超过10)

比如下图N=13 H=6 M=2。

1

2

3

2

3

2



输入描述 Input Description
第一行为三个整数、N、H、M。


第二行以后每行一个整数K,-1为结束符。


输出描述 Output Description
第一行为满足N、H、M的积木搭建方案总数(1<=N<=540 H<=60 M<=10)


以后每一行对于对应的K,给出顺序排列的第K种方案(最小的排列为第一种)。


(如样例中,2 1 2 3 2 3是一种方案,代表一层的积木分别为212323,232321也是一种方案,212323比232321要小,每个状态之间是可比的,第一个数小的排前面,第一个数相等的就看第二个数。那么所有方案就有一个顺序了,这里的K就是求第K个按顺序排列的方案)


样例输入 Sample Input
13 6 2
1
3
-1


样例输出 Sample Output
3
2 1 2 3 2 3

2 3 2 3 2 1

题目分析:

本题从数据范围来看每层可以扩展2个节点,最多60层,可能达到2^60,直接搜索加上重复计算,再加上数据记录,应该超时,

考虑到每种状态可以扩展两种状态,或者每种状态都只能由两种状态扩展而来,具有最优子结构,可以用动态规划由底层到上层计算。

假设当前层为第h层,从第一层向上递推,结束点为f[h][m][m]

f[hi][ni][mi]代表第hi层,总数积木为ni ,当前层积木的个数为mi,从底层向上动态规划

开始的边界条件为 f[1][i][i]=1;

f[hi][ni][mi]=f[hi-1][ni-mi][mi-1]+f[ni][ni-mi][mi+1]

根据字典序,先扩展mi-1节点。

查找第k个方案的时候,根据节点左右关系,比左节点小向左找,否则向右找。

#include<iostream>
#include<stdio.h>
using namespace std;
int n,h,m;
long long f[62][542][12]={0},k;//f[h][n][m]高度,总数,当前层积木个数
void dp(){
	int hi,ni,mi;
	for(mi=1;mi<=10;mi++)f[1][mi][mi]=1;
	for(hi=2;hi<=h;hi++)//h
	  for(ni=hi+1;ni<=n;ni++)//n
	    for(mi=1;mi<=10;mi++)//m		
	     if(ni-mi>=1){
	      f[hi][ni][mi]+=f[hi-1][ni-mi][mi-1];
	      if(mi<=9)f[hi][ni][mi]+=f[hi-1][ni-mi][mi+1];
	    }
}
void find(long long x,int hi,int ni,int mi){
	 printf("%d ",mi);
	 if(hi>=2)
	  if(x<=f[hi-1][ni-mi][mi-1])
	     find(x,hi-1,ni-mi,mi-1);
   	  else
   	     find(x-f[hi-1][ni-mi][mi-1],hi-1,ni-mi,mi+1);
	 
}
int main(){
   
	cin>>n>>h>>m;
	dp();
	cout<<f[h][n][m]<<endl;
	do{
		cin>>k;
		if(k==-1)break;
		find(k,h,n,m);
        printf("\n");
	}while(k!=-1);
return 0;
}

同理:也可以用记忆化化搜索,自定向下分拆,递归

6 13 2,两个分支:5 11 1, 5 11 3,先分解,计算,然后返回值。

注意1.已经计算过的顶点直接返回,做题的时候,直接用了f[][][]是否大于0判断记录,调试时候发现错了,需要另外定义一个vis,否则计算结果为0的节点将重复计算。

注意2:不可能的分支及时剪枝,原来只在两次dfs哪里小剪枝,很慢。重新思考后发现剪枝条件,ni/hi>10,ni/hi<1就不可能了,剪掉后很快,dp12ms ,搜索8ms。

#include<iostream>
#include<stdio.h>
#include<cstring>
using namespace std;
int n,h,m;
bool vis[62][542][12]={0};
long long f[62][542][12]={0},k;//h,n.m
long long dfs(int hi,int ni,int mi){
  if(ni/hi>10||ni/hi<1)return  f[hi][ni][mi]=0;	
  if(vis[hi][ni][mi])return f[hi][ni][mi];
  else{
	if(hi==1){
	    vis[hi][ni][mi]=true;
	    if(ni==mi&&mi<=10)		
	       return f[hi][ni][mi]=1;
	    else
	      return f[hi][ni][mi]=0;
	}
	if(hi>=2){	
	    long long t=0;
	    if(mi-1>=1) 
	       t+=dfs(hi-1,ni-mi,mi-1);
	    if(mi+1<=10) 
	       t+=dfs(hi-1,ni-mi,mi+1);
	   vis[hi][ni][mi]=true;
	   return f[hi][ni][mi]=t;
	}
  }
}


void find(long long x,int hi,int ni,int mi){
	 printf("%d ",mi);
	if(hi>=2)
	  if(x<=f[hi-1][ni-mi][mi-1])
	     find(x,hi-1,ni-mi,mi-1);
   	  else
   	     find(x-f[hi-1][ni-mi][mi-1],hi-1,ni-mi,mi+1);
	 
}
int main(){
 
	cin>>n>>h>>m;
	dfs(h,n,m);
	cout<<f[h][n][m]<<endl;
	do{
		cin>>k;
		if(k==-1)break;
		find(k,h,n,m);
        printf("\n");
	}while(k!=-1);
return 0;
}


考虑柔性负荷的综合能源系统低碳经济优化调度【考虑碳交易机制】(Matlab代码实现)内容概要:本文围绕“考虑柔性负荷的综合能源系统低碳经济优化调度”展开,重点研究在碳交易机制下如何实现综合能源系统的低碳化与经济性协同优化。通过构建包含风电、光伏、储能、柔性负荷等多种能源形式的系统模型,结合碳交易成本与能源调度成本,提出优化调度策略,以降低碳排放并提升系统运行经济性。文中采用Matlab进行仿真代码实现,验证了所提模型在平衡能源供需、平抑可再生能源波动、引导柔性负荷参与调度等方面的有效性,为低碳能源系统的设计与运行提供了技术支撑。; 适合人群:具备一定电力系统、能源系统背景,熟悉Matlab编程,从事能源优化、低碳调度、综合能源系统等相关领域研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①研究碳交易机制对综合能源系统调度决策的影响;②实现柔性负荷在削峰填谷、促进可再生能源消纳中的作用;③掌握基于Matlab的能源系统建模与优化求解方法;④为实际综合能源项目提供低碳经济调度方案参考。; 阅读建议:建议读者结合Matlab代码深入理解模型构建与求解过程,重点关注目标函数设计、约束条件设置及碳交易成本的量化方式,可进一步扩展至多能互补、需求响应等场景进行二次开发与仿真验证。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值