• 2021.6.8背包总结


    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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",i,dp[i]);
    	printf("%d",ans);
    	return 0;
    }
  • 相关阅读:
    假期小作业1
    Python_day4
    Python_day3
    Python_day2
    12/06
    12/05
    python系统学习:第三周之简单的三级菜单
    python系统学习:第二周之字典应用
    python系统学习:第二周之字符串函数练习
    python系统学习:第二周之购物车功能
  • 原文地址:https://www.cnblogs.com/conprour/p/14872587.html
Copyright © 2020-2023  润新知