蓝桥day9 algo-20*、21、29、30、31、34

本文介绍了使用动态规划解决二叉树的先序遍历、01背包问题以及区间处理问题。具体包括:根据中序和后序遍历构造先序遍历、01背包求解剩余空间最小值、处理区间覆盖问题以及通过动态规划优化纪念品分组,以达到最少分组数。文章深入浅出地展示了动态规划在不同场景下的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ALGO-20. 求先序排列列!!!!

问题描述
给出⼀一棵二叉树的中序与后序排列。求出它的先序排列列。(约定树结点⽤不同的⼤写字母表示,⻓度
<=8)。
输⼊入格式
两行,每行⼀个字符串,分别表示中序和后序排列
输出格式
⼀个字符串,表示所求先序排列
样例例输⼊入
BADC
BDCA
样例例输出
ABCD

#include<iostream>
#include<string.h>
using namespace std;
string in,post,ans="";
void pre(int root,int l,int r){
	if(l>r) return;
	int i=r;
	while(post[root]==in[i])
		i--;
	ans+=post[i];
	pre(root-1+i-1,l,i-1);
	pre(root-1,i+1,r);
	
}
int main(){
	
	cin>>in>>post;
	pre(post.length()-1,0,in.length()-1);
	cout<<ans;
	return 0;
	
}

这里采用递归的方法进行
同类型扩展:
知先序遍历、中序遍历求后序遍历:

#include <cstdio>
#include <cstring>
 
  const int maxn = 100;
  
  int n;
  char a[maxn], b[maxn];
  
  void dfs(int la, int ra, int lb, int rb) {
  	printf("%d %d %d %d",&la,&ra,&lb,&rb);
     if (la > ra)
         return;
     int md;
     for (md = la; a[md] != b[lb]; md ++);
     dfs(la, md - 1, lb + 1, lb + md - la);
     dfs(md + 1, ra, lb + md - la + 1, rb);
     putchar(b[lb]);
 }
 
 int main() {
     scanf("%s", b + 1);
     scanf("%s", a + 1);
     n = strlen(a + 1);
     dfs(1, n, 1, n);
     putchar(10);
 }

ALGO-21. 装箱问题(动态规划,01背包)

问题描述
  有⼀一个箱⼦子容量量为V(正整数,0<=V<=20000),同时有n个物品(0<n<=30),每个物品
有⼀一个体积(正整数)。
  要求n个物品中,任取若⼲干个装⼊入箱内,使箱⼦子的剩余空间为最⼩小。
输⼊入格式
  第⼀一⾏行行为⼀一个整数,表示箱⼦子容量量;
  第⼆二⾏行行为⼀一个整数,表示有n个物品;
  接下来n⾏行行,每⾏行行⼀一个整数表示这n个物品的各⾃自体积。
输出格式
  ⼀一个整数,表示箱⼦子剩余空间。
样例例输⼊入
24
6
8
3
12
7
9
7
样例例输出
0
思考:
一般这种寻求合不合适的方案用动态规划进行
dp[i][j]代表前i中东西放置到体积为j的包内
如果物品体积能够放进去:
可以选择放或者不放
dp[i][j]=max(dp[i-1][j],dp[i-1][j-t]+t)
如果物品体积不能够放进去:
dp[i][j]=dp[i-1][j]
最后输出v-dp[n][v]即可

#include<iostream>
#include<vector>
using namespace std;
int dp[31][20001];
int main(){
	int v,n;
	cin>>v>>n;
	int t;
	for(int i=1;i<=n;i++)
		{
			cin>>t;
		for(int j=1;j<=v;j++)
		{
			if(j>=t)
				dp[i][j]=max(dp[i-1][j],dp[i-1][j-t]+t);
			else
				dp[i][j]=dp[i-1][j];
		 } 
		}
	cout<<v-dp[n][v];
	return 0;
}

ALGO-29. 校⻔门外的树(区间处理理)

问题描述
  某校⼤大⻔门外⻓长度为L的⻢马路路上有⼀一排树,每两棵相邻的树之间的间隔都是1⽶米。我们可以把⻢马路路看
成⼀一个数轴,⻢马路路的⼀一端在数轴0的位置,另⼀一端在L的位置;数 轴上的每个整数点,即0,1,2,
……,L,都种有⼀一棵树。
  由于⻢马路路上有⼀一些区域要⽤用来建地铁。这些区域⽤用它们在数轴上的起始点和终⽌止点表示。已 知任
⼀一区域的起始点和终⽌止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树
(包括区域端点处的两棵树)移⾛走。你的任务是计算将这些树 都移⾛走后,⻢马路路上还有多少棵树。
输⼊入格式
  输⼊入⽂文件的第⼀一⾏行行有两个整数L(1 <= L <= 10000)和 M(1 <= M <= 100),L代表⻢马路路的⻓长
度,M代表区域的数⽬目,L和M之间⽤用⼀一个空格隔开。接下来的M⾏行行每⾏行行包含两个不不同的整数,⽤用⼀一个
空格隔开,表示⼀一个区域的起始点 和终⽌止点的坐标。
输出格式
  输出⽂文件包括⼀一⾏行行,这⼀一⾏行行只包含⼀一个整数,表示⻢马路路上剩余的树的数⽬目。
样例例输⼊入
500 3
150 300
100 200
470 471
样例例输出
298
数据规模和约定
  对于20%的数据,区域之间没有重合的部分;
  对于其它的数据,区域之间有重合的情况。

思考:
通过动态数组进行筛选就很简单了
注意它是由0开始的

#include<iostream>
#include<vector>
using namespace std;

int main(){
	int L,M;
	cin>>L>>M;
	vector<int >v(L+1,1);
	int a,b;
	int count=0;
	while(M--)
	{
		cin>>a>>b;
		for(int i=a;i<=b;i++)
			v[i]=0;
	}
	for(int i=0;i<=L;i++)
		if(v[i]==1)
			count++;
	cout<<count;
	return 0;
}

ALGO-30. ⼊入学考试(01背包,动态规划)

问题描述
  ⾠辰辰⾠辰辰是个天资聪颖的孩⼦子,他的梦想是成为世界上最伟⼤大的医师。为此,他想拜附近最有威望的
医师为师。医师为了了判断他的资质,给他出了了⼀一个难题。医师把他带到⼀一个到处都是草药的⼭山洞洞⾥里里对
他说:“孩⼦子,这个⼭山洞洞⾥里里有⼀一些不不同的草药,采每⼀一株都需要⼀一些时间,每⼀一株也有它⾃自身的价值。
我会给你⼀一段时间,在这段时间⾥里里,你可以采到⼀一些草药。如果你是⼀一个聪明的孩⼦子,你应该可以让
采到的草药的总价值最⼤大。”
  如果你是⾠辰辰⾠辰辰,你能完成这个任务吗?
输⼊入格式
  第⼀一⾏行行有两个整数T(1 <= T <= 1000)和M(1 <= M <= 100),⽤用⼀一个空格隔开,T代表总共能
够⽤用来采药的时间,M代表⼭山洞洞⾥里里的草药的数⽬目。接下来的M⾏行行每⾏行行包括两个在1到100之间(包括1
和100)的整数,分别表示采摘某株草药的时间和这株草药的价值。
输出格式
  包括⼀一⾏行行,这⼀一⾏行行只包含⼀一个整数,表示在规定的时间内,可以采到的草药的最⼤大总价值。
样例例输⼊入
70 3
71 100
69 1
1 2
样例例输出
3
数据规模和约定
  对于30%的数据,M <= 10;
  对于全部的数据,M <= 100。

思考:
看题目获得最大总价值就可以知道它是要通过动态规划进行
dp[i][j]代表前i秒采草时包内容量为j,整个值的大小表示的是采草药的最大价值
如果包内容量能够放进去:
可以选择放或者不放
dp[i][j]=max(dp[i-1][j],dp[i-1][j-t]+v)
如果包内容量不能够放进去:
dp[i][j]=dp[i-1][j]
最后输出dp[m][T]即可

#include<iostream>
#include<cstring>
using namespace std;
int dp[100][1000];

int main(){
	memset(dp,0,sizeof(dp));
	int T,m;
	cin>>T>>m;
	int t,v;
	for(int i=1;i<=m;i++)
	{
		cin>>t>>v;
		for(int j=1;j<=T;j++)
		{
			if(j>=t)
				dp[i][j]=max(dp[i-1][j],dp[i-1][j-t]+v);
			else 
				dp[i][j]=dp[i-1][j];
		}
	}
	cout<<dp[m][T];
	return 0;
}

ALGO-31. 开⼼心的⾦金金明(01背包,动态规划)

问题描述
  ⾦金金明今天很开⼼心,家⾥里里购置的新房就要领钥匙了了,新房⾥里里有⼀一间他⾃自⼰己专⽤用的很宽敞的房间。更更
让他⾼高兴的是,妈妈昨天对他说:
“你的房间需要购买哪些物品,怎 么布置,你说了了算,只要不不超过N元钱就⾏行行”。今天⼀一早⾦金金明就开始
做预算,但是他想买的东⻄西太多了了,
肯定会超过妈妈限定的N元。于是,他把每件物品规定了了⼀一 个重要度,分为5等:⽤用整数1~5表示,第
5等最重要。他还从因特⽹网上查到了了每件物品的价格(都是整数元)。他希望在不不超过N元(可以等于
N元)的前提 下,使每件物品的价格与重要度的乘积的总和最⼤大。
设第j件物品的价格为v[j],重要度为w[j],共选中了了k件物品,编号依次为 j1,j2,……,jk,则所
求的总和为:
  v[j1]*w[j1]+v[j2]w[j2]+ …+v[jk]w[jk]。(其中为乘号)
  请 你帮助⾦金金明设计⼀一个满⾜足要求的购物单。
输⼊入格式
  输⼊入⽂文件 的第1⾏行行,为两个正整数,⽤用⼀一个空格隔开:
  N m
  (其中N(<30000)表示总钱 数,m(<25)为希望购买物品的个数。)
  从第2⾏行行到第m+1⾏行行,第j⾏行行给出了了编号为j-1的物品的基本数据,每⾏行行有2个⾮非负整数
  v p
  (其中v表示该物品的价格(v<=10000),p表示该物品的重要度(1~5))
输出格式
  输出⽂文件只有⼀一个正整数,为不不超过总钱数的物品的价格与重要度乘积的总和的最⼤大值
(<100000000)。
样例例输⼊入
1000 5
800 2
400 5
300 5
400 3
200 2
样例例输出
3900
思考:
老样子!获得最大值即是动态规划问题,分为买或者不买
dp[i][j]表示对于前i件物品选择部分购买限定总价不不超过j元后,物品的价格与重要程度乘积的总和的最
大值
可得dp[m][n]即是所求的解。
1.当当前输⼊入的物品价格⼤大于允许的最⼤大总价j元,则不不买,dp[i][j] = dp[i-1][j];
2.当当前输⼊入的物品体积⼩小于等于允许的最⼤大总价j元,考虑买或者不不买两种状态,取物品的价格与重
要程度乘积的总和最⼤大的那个:dp[i][j]=max(dp[i-1][j],dp[i-1][j-v]+v
p);

#include<iostream>
#include<cstring>
using namespace std;

int dp[25][30000];
int main(){
	memset(dp,0,sizeof(dp));
	int N,m;
	cin>>N>>m;
	int v,p;
	for(int i=1;i<=m;i++)
	{
		cin>>v>>p;
		for(int j=1;j<=N;j++)
		{
			if(j>=v)
				dp[i][j]=max(dp[i-1][j],dp[i-1][j-v]+v*p);
			else 
				dp[i][j]=dp[i-1][j];
			
		}
	}
	cout<<dp[m][N];
	return 0;
}

ALGO-34. 纪念品分组(贪⼼心算法+排序)

问题描述
  元旦快到了了,校学⽣生会让乐乐负责新年年晚会的纪念品发放⼯工作。为使得参加晚会的同学所获得的
纪念品价值 相对均衡,他要把购来的纪念品根据价格进⾏行行分组,但每组最多只能包括两件纪念品,并
且每组纪念品的价格之和不不能超过⼀一个给定的整数。为了了保证在尽量量短的时 间内发完所有纪念品,乐
乐希望分组的数⽬目最少。
  你的任务是写⼀一个程序,找出所有分组⽅方案中分组数最少的⼀一种,输出最少的分组数⽬目。
输⼊入格式
  输⼊入包含n+2⾏行行:
  第1⾏行行包括⼀一个整数w,为每组纪念品价格之和的上限。
  第2⾏行行为⼀一个整数n,表示购来的纪念品的总件数。
  第3~n+2⾏行行每⾏行行包含⼀一个正整数pi (5 <= pi <= w),表示所对应纪念品的价格。
输出格式
  输出仅⼀一⾏行行,包含⼀一个整数,即最少的分组数⽬目。
样例例输⼊入
100
9
90
20
20
30
50
60
70
80
90
样例例输出
6

#include<iostream>
#include<algorithm>
using namespace std;

int main(){
	int w,n;
	cin>>w>>n;
	int s[n];
	int count=0;
	for(int i=0;i<n;i++)
	{
		cin>>s[i];
			
	}
	sort(s,s+n);
	for(int i=0;i<n;i++)
	{
		if(s[i]>4)
			for(int j=0;j<=n;j++)
				if(s[n-j]>4&&(s[i]+s[n-j]<=w))
				{
						count++;
						s[i]=s[n-j]=1;
						break;
				}
	}
	for(int i=0;i<n;i++)
		if(s[i]>=5)
			count++;
	cout<<count;
	return 0;
}

我的方法太麻烦,要经历多次遍历
这种方法就简单多了:
首先排好顺序,i和j两两组合,若能组合的就成为一组,若i和j不能组合在一起,i-1和j更不能组合在一起,所以j只能自己成为一组了(这样可以避免后序在经历一次遍历),这时只需要看i能不能和j-1有一次遍历
循环的条件是i<=j,假设i和j相邻,便尝试一下两两能不能组合;如果不不满⾜足把它们放⼊⼀一组,那么j放⼊⼀组后j移动指针,使i == j,继续进⼊入循环;
当i == j的时候,因为这个单独的物品已经没有可以组合的物品剩余了,所以此时还要进⼊循环进行一
次 count++ 的计数操作~

#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
int main() {
int w, n;
scanf("%d %d", &w, &n);
int *a = new int[n];
for(int i = 0; i < n; i++)
scanf("%d", &a[i]);
sort(a, a+n);
int i = 0, j = n-1, cnt = 0;
while(i <= j) {
if(a[i] + a[j] <= w) {
i++;
}
cnt++;
j--;
}
cout << cnt;
return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值