week11 -背包问题

背包问题

01背包

用子问题来定义状态

  • 设计状态: f[i][j]表示仅考虑前 i 件物品,放入一个容量为 j 的背包可以获得的最大价值。
  • 状态转移方程:f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+v[i])
    表示第i件物品放与不放
  • 结果:如果设计状态为至多j,结果为f[N][V],恰好为j,结果为max(f[N][i])
  • 滚动数组优化后:
for(int i=0;i<=v;i++) f[i]=0;
for(i=1;i<=N;i++)
for(int j=V;j>=0;j--)
{     if(j-w[i]>0)
       f[j]=max(f[j],f[j-w[i]]+v[i])
}
ans=f[V]

完全背包

特点:每种物品有无数件,可以选择 0 或多件

  • 0-1背包时,因为要保证第 i 次循环中的状态 f[i][j] 是从状态 f[i-1][j-w[i]]递推而来,为了保证“物品只选一次”而逆序。即“选入第 i 件物品”的策略时,依据的是一个绝无已经选入第 i 件物品的子结果 f[i-1][j-w[i]]
  • 现在完全背包考虑“加选一个物品”时,正需要一个可能已选入第 i 种物品的子结果 f[i][j-w[i]],所以必需采用正序循环。
for(int j=0;j<=v;j++) f[j]=0;
for(int i=1;i<=n;i++)
{
	for(int j=0;j<=v;j++)
	if(j-w[i]>=0)
	f[j]=max(f[j],f[j-w[i]]+v[i]);
 } 
ans=f[V]

多重背包

特点:每种物品有 有限件Ci
解决:采用进制的思想将 Ci 进行二进制拆分,然后转换成 0-1背包问题
保证:拆分后的组合进行选、不选的 0-1 背包的决策,就能涵盖所有 0~Ci 中
的决策。从而转换成了 0-1 背包问题

  • 二进制拆分后 N->cnt
int cnt=0;
for(int i=1;i<=n;i++)
{
	int t=c[i];
	for(int k=1;k<=t;k<<=1)
	{
		cnt++;
		vv[cnt]=k*v[i];ww[cnt]=k*w[i];
		t=t-k;
	}
	if(t>0)
	{
		cnt++;
		vv[cnt]=t*v[i];ww[cnt]=t*w[i];
	}
 }
 for(int i=0;i<=v;i++) f[i]=0;
 for(int i=1;i<=cnt;i++)
 {
 	for(int j=v;j>=0;j--)
 	{
 	
 		if(j-ww[i]>=0)
 		f[j]=max(f[j],f[j-ww[i]]+vv[i]);
	 }
 }

题目一东东与ATM

题意

一家银行计划安装一台用于提取现金的机器。
机器能够按要求的现金量发送适当的账单。
机器使用正好N种不同的面额钞票,例如D_k,k = 1,2,…,N,并且对于每种面额D_k,机器都有n_k张钞票。
例如,
N = 3,
n_1 = 10,D_1 = 100,
n_2 = 4,D_2 = 50,
n_3 = 5,D_3 = 10
表示机器有10张面额为100的钞票、4张面额为50的钞票、5张面额为10的钞票。
东东在写一个 ATM 的程序,可根据具体金额请求机器交付现金。
注意,这个程序计算程序得出的最大现金少于或等于可以根据设备的可用票据供应有效交付的现金。

输入

程序输入来自标准输入。 输入中的每个数据集代表特定交易,其格式为:Cash N n1 D1 n2 D2 … nN DN其中0 <= Cash <= 100000是所请求的现金量,0 <= N <= 10是 纸币面额的数量,0 <= nk <= 1000是Dk面额的可用纸币的数量,1 <= Dk <= 1000,k = 1,N。 输入中的数字之间可以自由出现空格。 输入数据正确

输出

对于每组数据,程序将在下一行中将结果打印到单独一行上的标准输出中。

代码

 #include<iostream>
using namespace std;
int c[15];int w[15];int f[100010];
int main()
{   
  int v;
  while(cin>>v)
  {   int n;cin>>n;
       for(int i=1;i<=n;i++)
       cin>>c[i]>>w[i];
       int cnt=0;int ww[10020];
for(int i=1;i<=n;i++)
{
	int t=c[i];
	for(int k=1;k<=t;k<<=1)
	{
		cnt++;
	   ww[cnt]=k*w[i];
		t=t-k;
	}
	if(t>0)
	{
		cnt++;
		ww[cnt]=t*w[i];
	}
 }
 for(int i=0;i<=v;i++) f[i]=0;
 for(int i=1;i<=cnt;i++)
 {
 	for(int j=v;j>=0;j--)
 	{
 		if(j-ww[i]>=0)
 		f[j]=max(f[j],f[j-ww[i]]+ww[i]);
	 }
 }
  	cout<<f[v]<<endl;
  }return 0;

 } 
  

题目二 东东开车了

题意

东东开车出去泡妞(在梦中),车内提供了 n 张CD唱片,已知东东开车的时间是 n 分钟,他该如何去选择唱片去消磨这无聊的时间呢

假设:

CD数量不超过20张
没有一张CD唱片超过 N 分钟
每张唱片只能听一次
唱片的播放长度为整数
N 也是整数
我们需要找到最能消磨时间的唱片数量,并按使用顺序输出答案(必须是听完唱片,不能有唱片没听完却到了下车时间的情况发生)

输入

多组输入

每行输入第一个数字N, 代表总时间,第二个数字 M 代表有 M 张唱片,后面紧跟 M 个数字,代表每张唱片的时长 例如样例一: N=5, M=3, 第一张唱片为 1 分钟, 第二张唱片 3 分钟, 第三张 4 分钟

所有数据均满足以下条件:

N≤10000
M≤20

输出

输出所有唱片的时长和总时长,具体输出格式见样例

代码

#include<iostream>
#include<cstring>
using namespace std;
int f[10010];int w[25];
int main()
{
	int v;
	while(cin>>v)
	{
		int n;cin>>n;
		for(int i=1;i<=n;i++)
		cin>>w[i];int path[25][10010];memset(path,0,sizeof(path));
		 for(int j=0;j<=v;j++) f[j]=0;
		int sel[25];memset(sel,0,sizeof(sel));
   for(int i=1;i<=n;i++)
{
	for(int j=v;j>=0;j--)
	{   
		if(j-w[i]>=0)
		{ if(f[j]<f[j-w[i]]+w[i])
		path[i][j]=1;
		f[j]=max(f[j],f[j-w[i]]+w[i]);	
		}
		
	}
 } int k=0;
    for(int j=v,i=n;j>=0&&i>=0;i--)
    {
    	if(path[i][j])
    	{   sel[k++]=w[i];
    		j=j-w[i];
		}
	}
	for(int i=k-1;i>=0;i--)
	cout<<sel[i]<<" ";
  cout<<"sum:"<<f[v]<<endl;
	}
}
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你好!对于心脏病预测的问题,使用循环神经网络(RNN)是一种常见的方法。RNN适用于处理序列数据,而心电图信号就是一种序列数据。在使用RNN进行心脏病预测时,你可以将心电图信号作为输入序列,然后通过训练RNN模型来预测患者是否患有心脏病。 首先,你需要准备一个合适的数据集,其中包含心电图信号和相应的心脏病标签。可以使用公开的心电图数据集,如PTB数据库或MIT-BIH数据库。然后,你可以对数据进行预处理和特征工程,如数据清洗、滤波、降采样等。 接下来,你可以构建一个RNN模型。RNN模型由一系列循环层组成,每个循环层都会处理一个时间步的输入数据。你可以选择不同类型的RNN单元,如简单循环单元(SimpleRNN)、长短期记忆网络(LSTM)或门控循环单元(GRU)。通过添加适当的全连接层和激活函数,你可以将RNN模型输出映射到二类问题(有或无心脏病)的结果。 然后,你可以使用训练集对RNN模型进行训练,并使用验证集进行模型调优。在训练过程中,你可以使用适当的损失函数(如交叉熵)和优化算法(如随机梯度下降)来最小化模型的预测误差。 最后,你可以使用测试集对训练好的模型进行评估,并计算模型的性能指标,如准确率、精确率、召回率等。这些指标可以帮助你评估模型的预测能力和泛化能力。 需要注意的是,心脏病预测是一个复杂的医学问题,仅仅使用心电图信号可能不能得到准确的预测结果。通常情况下,还需要结合其他患者的临床信息和医学知识来进行综合评估。因此,在进行心脏病预测时,建议与专业医生合作,并遵循相关的医学准则和规范。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值