nowcoder 2020/6/20 J-小梁的背包

小梁来到了伽勒尔地区并参加了联盟赛热身赛,比赛小岛上有n个精灵散落在岛上各处,她有一个大小为s的背包,每个精灵的战斗值为vi,体积为wi。
请问在她临走之前背包内宝可梦的战斗力总和最多为多少,并输出其战斗值总和sum以及背包内的精灵数量ans。

示例1
输入

1
5 5
1 3
2 5
1 2
4 2
6 1

输出

10 3

背包问题,问了同学他说好像是多重背包?
赛后搜得:背包问题详解

这题恶心的地方是用dp求出最大的价值后还要让你计数,问放进去了多少个精灵球,卡了非常久。

dp部分:
我原本将这个计数的设为是cnt[i][j]=cnt[i-1][j];
然后if判断是否放入,放入则cnt[i][j]++。这样是错误的,因为价值更新的话应该是前面那个容量的背包的次数再加一,而不是简单的++。
应该改为

cnt[i][j]=cnt[i-1][j];	

//.....

cnt[i][j]=cnt[i-1][j-g[i].w]+1;

正解:

	for(int i=1;i<=n;i++){
		for(int j=0;j<=s;j++){
			dp[i][j]=dp[i-1][j];
			cnt[i][j]=cnt[i-1][j];	
			if(j>=g[i].w){
				if(dp[i-1][j-g[i].w]+g[i].v>dp[i-1][j]){
					dp[i][j]=dp[i-1][j-g[i].w]+g[i].v;
					cnt[i][j]=cnt[i-1][j-g[i].w]+1;
				}				
			}
		}
	}

完整代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;

struct gg{
	int v,w;
}g[N];
int dp[N][N];
int cnt[N][N];
void solve()
{
	int n,s;
	cin>>n>>s;
	for(int i=1;i<=n;i++)cin>>g[i].w>>g[i].v;
	for(int i=1;i<=n;i++){
		for(int j=0;j<=s;j++){
			dp[i][j]=dp[i-1][j];
			cnt[i][j]=cnt[i-1][j];	
			if(j>=g[i].w){
				if(dp[i-1][j-g[i].w]+g[i].v>dp[i-1][j]){
					dp[i][j]=dp[i-1][j-g[i].w]+g[i].v;
					cnt[i][j]=cnt[i-1][j-g[i].w]+1;
				}				
			}
		}
	}
	cout<<dp[n][s]<<" "<<cnt[n][s]<<endl;
}

int main()
{
	ios::sync_with_stdio(false);	
	int t;
	cin>>t;
	while(t--)solve();
	return 0;
}

dp仍然是我比较不熟练的部分,需要多做相关的题目。

6/21 优化

经同学提议优化了一下,将数组开成1维,节省了非常多的空间。
需要注意的是枚举s的时候需要从后往前,不能从前往后,否则会变成完全背包(每个精灵有无数只),而本题需要的是01背包(每个精灵只有一只)。

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;

struct gg{
	int v,w;
}g[N];
int dp[N];
int cnt[N];
void solve()
{
	memset(dp,0,sizeof(dp));
	memset(cnt,0,sizeof(cnt));
	int n,s;
	cin>>n>>s;
	for(int i=1;i<=n;i++)cin>>g[i].w>>g[i].v;
	for(int i=1;i<=n;i++){
		for(int j=s;j>=g[i].w;j--){//从s开始
			if(dp[j-g[i].w]+g[i].v>dp[j]){
				dp[j]=dp[j-g[i].w]+g[i].v;
				cnt[j]=cnt[j-g[i].w]+1;				
			}
		}
	}
	cout<<dp[s]<<" "<<cnt[s]<<endl;
}
	
int main()
{
	ios::sync_with_stdio(false);	
	int t;
	cin>>t;
	while(t--)solve();
	return 0;
}
posted @ 2020-06-20 18:35  LiangYC1021  阅读(132)  评论(0编辑  收藏  举报