0
点赞
收藏
分享

微信扫一扫

习题整理(简单01背包 可用查并集2022/4/24)

静悠 2022-04-24 阅读 40
python算法

习题整理

提示:之前的习题在习题集合


文章目录


提示:以下是本篇文章正文内容,下面案例可供参考

一、诱人的宝藏

题目:勇敢的小明来到一个失落的村庄。他非常幸运,找到了很多宝藏和一个空的大铁箱,但是失落的村庄里有很多愤怒的僵尸。小明非常勇敢,他决定打败僵尸,然后把所有的宝藏都带回来。一场旷日持久的残酷战斗从早到晚持续,最后小明发现僵尸是不死的,不可战胜的。
但是,这些宝藏不应该留在这里。不幸的是,由于大铁箱容量的限制,小明无法携带所有宝藏。村庄里的宝藏只有两种:祖母绿宝石和蓝宝石。所有的宝石在大小和价值上都是相等的,数量是无穷的。
聪明得你,能不能考虑到箱子的大小、每种宝石的价值和大小,计算出我们的勇士小明能带回的宝藏的最大价值。

输入输出格式
输入格式
输入只有一行,包含五个整数 N,S1,V1 ,S2,V2
​,表示宝箱的大小为 N,祖母绿宝石的大小和价值为 S1
和V1,蓝宝石的大小和价值为 S2和 V 2。所有整数都是正整数。整数之间以空格间隔。
输出格式
针对输入,打印出小明可以随身携带的所有宝藏的最大总值。
输入输出样例1
输入
100 1 1 2 2
输出
100

1.思路

  • 这道题本身其实是弱化的01背包问题,但我们不用动态规划做。而是换一个思路。 我们只需要考虑两种情况
  • 第一种先装绿宝石装到装不下,剩余的空间去装蓝宝石
  • 第二种先装蓝宝石装到装不下,剩余的空间去装绿宝石 然后我们比较这两种情况,哪一种的价值最大?输出即可

2.代码

a=input() #输入的那一行就是背包容量,绿宝石重量和价值,蓝宝石的重量和价值  
a=a.split() #以空格作为分隔符,将整个字符串分割成列表返回  
a=[int(i) for i in a]  
b=max((a[0]//a[1])*a[2]+((a[0]%a[1])//a[3])*a[4],(a[0]//a[3])*a[4]+((a[0]%a[3])//a[1])*a[2])#这一句就是判断那两种情况,哪一种的价值更大?  
#(a[0]//a[1])*a[2]+((a[0]%a[1])//a[3])*a[4]先装绿宝石,再装蓝宝石  
print(b)

二、晚宴

题目:今天是小明的生日,他邀请了很多朋友。到了吃晚饭的时间,小明想知道他至少需要多少张桌子。你必须知道,并不是所有的朋友都认识彼此,而且所有的朋友都不想和陌生人待在一起。
这个问题的一个重要规则是,如果我告诉你 A 认识 B,B 认识 C,这意味着 A,B,C 相互认识,所以他们可以待在一张桌子上。
例如:如果我告诉你 A 知道 B,B 知道 C,D 知道 E,那么 A,B,C 可以待在一张桌子上,而 D,E 必须待在另一张桌子上。所以小明至少需要两张桌子。

输入输出格式
输入格式
第一行有两个整数 n 和 m,分别表示朋友的数量和朋友之间关系的数量,朋友标记为从 1 到 n;
然后是 m 行。每一行由两个整数 A 和 B(A!=B) 组成,这意味着朋友 A 和朋友 B 彼此认识。
整数之间以空格间隔。

输出格式
针对输入,打印出小明最少需要多少张桌子。

输入输出样例1
输入
5 3
1 2
2 3
4 5
输出
2

1.思路

  • 这道题理清逻辑后还是比较简单的
  • 首先要先确定一点,最初始有n个朋友就需要有n张桌子,因为我们不确定他们认不认识?
  • 接下来会有n对关系,只分两种情况
  • 第一种是两个元素,之前都没出现过,再给出这段关系后,他们两个就可以坐一张桌子,原本两个人要两张桌子,现在两个人要一张桌子,所以桌子数量减一
  • 第二种是两个元素,之前出现过一个元素,然后又有一个新的元素,这个时候我们就要新的元素,跟那个老的元素去做一张桌子,所以也是桌子数量减一
  • 根据这个关系,我们可以看出来,无论是哪一种情况,其实都是桌子的数量减一,所以我们直接拿朋友的总数减去出现的关系数目就可以了.
  • 以这道题的输出样例来解释,刚开始输入有五个朋友,所以初始有五张桌子
  • 然后有三对关系,第一对出现了1和2,所以1和2可以坐一张桌子。两个人去坐一张桌子,省去了一张桌子,所以桌子数量减一。
  • 第二对关系,是2和3。2之前出现过3是新的朋友,根据题里的规则,3可以去和1,2坐一张桌子,所以又省去了一张桌子。
  • 第三对关系,4和5就同第一对关系一样减去一张桌子。所以就是,五个人减去三对关系,得两张桌子

2.代码

b=input()  
b=b.split()  
b=[int(i) for i in b]  
print(b[0]-b[1]) #无论是哪一种情况,其实都是桌子的数量减一,所以我们直接拿朋友的总数减去出现的关系数目

三、医师之路

题目:
小明从小的梦想就是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”
如果你是小明,你能完成这个任务吗?

输入输出格式
输入格式
输入第一行包含 2 个整数 t 和 m,t 表示总共能够用来采药的时间,m 表示山洞里的草药的数目。
接下来输入 m 行,每行包括 2 个整数 c 和 v,分别表示采摘某株草药的时间和这株草药的价值。
整数之间以空格间隔。
输出格式
针对输入,打印出小明在规定的时间内可以采到的草药的最大总价值。

输入输出样例1
输入
70 3
71 100
69 1
1 2
输出
3

1.思路

这道题的题型主要就是01背包问题,他只不过是把01背包问题里面的体积换成了时间。
接下来我会分别介绍如何用动态规划解这道题和01背包问题的模板。
动态规划简单来说就是我们利用历史数据去推出新的数据来,减少我们的计算量。
我也不会着重介绍,最优子结构跟重复子问题,我就简单讲一下,怎么解题?
动态规划的题可以分为三部:
第一步我们要确定我们数组里的每个元素代表的是什么含义
第二步,我们要确定初始值该怎么设立?
第三步,我们要确定如何用历史数据去推出新的数据。
我会以下面这道题为例,讲一下上面三个步骤该如何去做。
第一步,我们设一个二维数组dp,dp[i][j]代表的元素就是在我时间j范围内,采集i个药草,所能采集到的最大价值。
第二步,由于我一开始i=0的时候,我的价值肯定是零,所以我的初始值就是零。
第三步,我们如何从历史数据中推出新的数据呢?我们要分两种情况。就是我第i个药材采还是不采?在此之前,我们首先要判断我们现在的时间j是否大于采集第i个药材所需的时间。如果小于的话,我肯定是不能踩的了。所以我的最大价值肯定是,在相同时间内,前i-1个药材的最大价值。
如果我的时间大于了第i个草的时间我会去比较,我采第i个药草和不采第i个药草,那个价值哪个更高?取最大的就ok。可能有同学认为采第i个药草,肯定价值要更大呀。
但我们要注意一点,我们采摘药草是有时间限制的,所以如果我们要采第i个药草,我们就要去把空出第i个药草时间。采第i个药草价值,就是减j减去采第i个药草的时间下标的价值,加上第i个药草价值。

2.扩展知识

(1)np.zeros()的作用
返回来一个给定形状和类型的用0填充的数组
zeros(shape, dtype=float, order=‘C’)
shape:表示形状
dtype:数据类型,可选参数,默认numpy.float64
order:可选参数,c代表行优先;F代表列优先
(2)01背包问题

  • 在解决问题之前,为描述方便,首先定义一些变量:Vi表示第 i 个物品的价值,Wi表示第 i 个物品的体积,定义V(i,j):当前背包容量
    j,前 i 个物品最佳组合对应的价值,同时背包问题抽象化(X1,X2,…,Xn,其中 Xi 取0或1,表示第 i 个物品选或不选)。
  • 寻找递推关系式,面对当前商品有两种可能性:
    包的容量比该商品体积小,装不下,此时的价值与前i-1个的价值是一样的,即V(i,j)=V(i-1,j);
  • 还有足够的容量可以装该商品,但装了也不一定达到当前最优价值,所以在装与不装之间选择最优的一个,即
    V(i,j)=max{V(i-1,j),V(i-1,j-w(i))+v(i)}
    其中V(i-1,j)表示不装,V(i-1,j-w(i))+v(i) 表示装了第i个商品,背包容量减少w(i),但价值增加了v(i);
    由此可以得出递推关系式:
j<w(i)   V(i,j)=V(i-1,j)  
j>=w(i)   
V(i,j)=max{V(i-1,j),V(i-1,j-w(i))+v(i)
  • 这里需要解释一下,为什么能装的情况下,需要这样求解(这才是本问题的关键所在!):
    可以这么理解,如果要到达V(i,j)这一个状态有几种方式?
  • 肯定是两种,第一种是第i件商品没有装进去,第二种是第i件商品装进去了。没有装进去很好理解,就是V(i-1,j);装进去了怎么理解呢?如果装进去第i件商品,那么装入之前是什么状态,肯定是V(i-1,j-w(i))。由于最优性原理(上文讲到),V(i-1,j-w(i))就是前面决策造成的一种状态,后面的决策就要构成最优策略。两种情况进行比较,得出最优。

3.代码

import numpy as n  
dp=n.zeros((1000,1000),dtype=int)#这一步是创建一个int类型二维的dp数组,1000行1000列。  
yao=n.zeros((100,2),dtype=int)  
a=input()  
a=a.split()#以空格为分隔,符将字符串分割成一个列表返回  
t=int(a[0])  
m=int(a[1])  
for i in range(1,m+1):#这一部是输入所有药材采集的时间和价值  
    a=input()  
    a=a.split()  
    yao[i][0]=int(a[0])  
    yao[i][1]=int(a[1])  
for i in range(1,m+1):#01背包模板  
    for j in range(1,t+1):  
        if(j<yao[i][0]):  
            dp[i][j]=dp[i-1][j]  
        else:  
            dp[i][j]=dp[i-1][j] if dp[i-1][j]>dp[i-1][j-yao[i][0]]+yao[i][1] else dp[i-1][j-yao[i][0]]+yao[i][1]#if的紧凑形式  
print(dp[m][t])   

总结

提示:技术太菜,后期补充,恳请大佬指正

举报

相关推荐

0 条评论