ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2021.6.8背包总结

2021-06-10 20:01:24  阅读:148  来源: 互联网

标签:总结 背包 ma 2021.6 int ll long -- dp


T1


解析:二维01背包板子,不多赘述

#include<bits/stdc++.h>
using namespace std;
const int N = 405;
int w1[N],w2[N],val[N],dp[N][N];
int m1,m2,n;
int main()
{
	scanf("%d%d",&m1,&m2);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d%d%d",&val[i],&w1[i],&w2[i]);
	for(int i=1;i<=n;i++)
		for(int j=m1;j>=w1[i];j--)
			for(int k=m2;k>=w2[i];k--)
				dp[j][k]=max(dp[j][k],dp[j-w1[i]][k-w2[i]]+val[i]);
	printf("%d\n",dp[m1][m2]);
	return 0;
}
/*
6 5
4
10 2 2 
20 3 2
40 4 3
30 3 3
*/

T2

解析:输出答案就是简单的有限背包,关键在于如何输出路径。过程中num[i][j]表示第i个物品在总体积达到j时选了多少个

最后递归输出路径,但是要先找到达到最大价值所需的最少费用(now),否则输出就会错乱

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 505;
int n,m,p[N],w[105];
ll eff[105][105],sum;
ll ans[N][N];
ll dp[N][N];
ll num[N][N];
ll pre[N];
void print(int i,int now)
{
	if(!i) return;
	print(i-1,now-num[i][now]*w[i]);
	printf("%d\n",num[i][now]);
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&w[i],&p[i]);
		for(int j=1;j<=p[i];j++)
		{
			scanf("%lld",&eff[i][j]);
		}
	}
	for(int i=1;i<=n;i++)
		for(int j=m;j>=w[i];j--)
			for(int k=1;k<=p[i];k++)
				if(j>=k*w[i]) 
				{
					if(dp[j][0]<dp[j-k*w[i]][0]+eff[i][k])
					{
						dp[j][0]=dp[j-k*w[i]][0]+eff[i][k];
						num[i][j]=k;
					}
				}
	int now=m;
	printf("%lld\n",dp[m][0]);
	while(dp[now][0]==dp[now-1][0]) now--;
	print(n,now);
	return 0;
}
/*
3 10
1 3 1 2 2 
2 3 2 4 6 
3 3 2 1 10
*/

(或者也可以用dp记录每个物品怎么选)

代码如下

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 505;
int n,m,p[N],w[105];
ll eff[105][105],sum;
ll ans[N][N];
ll dp[N][N];
ll pre[N];
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&w[i],&p[i]);
		for(int j=1;j<=p[i];j++)
		{
			scanf("%lld",&eff[i][j]);
		}
	}
	for(int i=1;i<=n;i++)
		for(int j=m;j>=w[i];j--)
			for(int k=1;k<=p[i];k++)
				if(j>=k*w[i]) 
				{
					if(dp[j][0]<dp[j-k*w[i]][0]+eff[i][k])
					{
						dp[j][0]=dp[j-k*w[i]][0]+eff[i][k];
						//printf("花费%d时,第%d种魔法升级为%d\n",j,i,k); 
						//
							dp[j][i]=k;
							for(int a=i-1;a>=1;a--)
							dp[j][a]=dp[j-k*w[i]][a];
					}
					if(dp[j-k*w[i]][0]+eff[i][k]==dp[j][0]){
					int sum1=0,sum2=0;
					for(int a=1;a<=n;a++){
						sum1+=w[a]*dp[j][a];
					}
					sum2+=k*w[i];
					for(int a=i-1;a>=1;a--){
						sum2+=w[a]*dp[j-k*w[i]][a];
					}
					if(sum2<sum1){
						dp[j][i]=k;
						for(int a=i-1;a>=1;a--){
							dp[j][a]=dp[j-k*w[i]][a];
						}
					}
				}
					
				}
	for(int i=0;i<=n;i++)
		printf("%d\n",dp[m][i]);
	return 0;
}
/*
3 10
1 3 1 2 2 
2 3 2 4 6 
3 3 2 1 10
*/

T3

解析:把每个有果子的树取出来,就变成了费用为2*(i+j)的多重背包。

   注意事项:

  • dp数组开到N*N
  • 体力最后不能为0
#include<bits/stdc++.h>
using namespace std;
const int N = 105;
#define ll long long
int mp[N][N],n,m,a,b,m1,m2;
ll dp[N];
int p[N*N],w[N*N],cnt,val[N*N];
int main()
{
	scanf("%d%d%d%d",&a,&b,&m1,&m2);
	m2--;
	m=min(m1,m2);
	for(int i=1;i<=a;i++)
		for(int j=1;j<=b;j++)
		{
			scanf("%d",&mp[i][j]);
			w[++cnt]=2*(i+j),val[cnt]=mp[i][j];
		}
	cnt=0;
	for(int i=1;i<=a;i++)
		for(int j=1;j<=b;j++)
		{
			int tmp;
			scanf("%d",&tmp);
			p[++cnt]=tmp;
		}
	for(int i=1;i<=cnt;i++)
		for(int j=m;j>=w[i];j--)
			for(int k=1;k<=p[i];k++)
				if(j>=k*w[i])
				dp[j]=max(dp[j],dp[j-k*w[i]]+k*val[i]);
	printf("%lld",dp[m]);
	return 0;
}
/*
4 4 13 20
10 0 0 0 
0 0 10 0
0 0 10 0
0 0 0 0
1 0 0 0
0 0 2 0 
0 0 4 0
0 0 0 0 
*/

T4

解析:经典题

分类讨论:

  • 只选择当前主件
  • 选择当前主件和第1个附件
  • 选择当前主件和第2个附件
  • 选择当前主件和第1、2个附件
#include <bits/stdc++.h>
#define fo(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;
const int INF = 0x3f3f3f3f,N = 3.2e4+5 , M = 1e2+5;
typedef long long ll;
typedef unsigned long long ull;
inline ll read(){
	ll ret = 0 ;char ch = ' ' , c = getchar();
	while(!(c >= '0' && c <= '9'))ch = c , c = getchar();
	while(c >= '0' && c <= '9')ret = (ret << 1) + (ret << 3) + c - '0' , c = getchar();
	return ch == '-' ? -ret : ret;
}
int n,m;
int w[M],v[M],ma[M][3],cnt,cntm,wa[M],va[M]; 
int dp[N],to[N];
signed main(){
	n = read() , m = read();
	int a,b,c;
	for(int i = 1 ; i <= m ; i ++){
		a = read() , b = read() , c = read();
		if(!c)
			to[i] = ++cnt,w[cnt] = a, v[cnt] = b * a;
		else
			 ma[to[c]][ ++ma[to[c]][0] ] = ++cntm , wa[cntm] = a , va[cntm] = b * a;
	}
	for(int i = 1 ; i <= cnt ; i ++){
		for(int j = n ; j >= w[i] ; j --){
			dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
			if(j >= w[i] + wa[ma[i][1]])
				dp[j] = max(dp[j],dp[j-w[i]-wa[ma[i][1]]] + v[i] + va[ma[i][1]]);
			if(j >= w[i] + wa[ma[i][2]])
				dp[j] = max(dp[j],dp[j-w[i]-wa[ma[i][2]]] + v[i] + va[ma[i][2]]);
			if(j >= w[i] + wa[ma[i][1]] + wa[ma[i][2]])
				dp[j] = max(dp[j],dp[j-w[i]-wa[ma[i][1]]-wa[ma[i][2]]] + v[i] + va[ma[i][1]] + va[ma[i][2]]);
		}
	}
	int ans = -INF;
	for(int i = 0 ; i <= n ; i ++)
		ans = max(ans,dp[i]);
//		printf("%d:%d\n",i,dp[i]);
	printf("%d",ans);
	return 0;
}

标签:总结,背包,ma,2021.6,int,ll,long,--,dp
来源: https://www.cnblogs.com/conprour/p/14872587.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有