zoukankan      html  css  js  c++  java
  • DP基础(背包问题)

    目录

    01背包模板

    多重背包模板

    完全背包模板

    例题

    A:HDU-2546 饭卡

    B:HDU-1171 Big Event in HDU

    C:HDU-2602 Bone Collector

    D:HDU-2639 Bone Collector II

    E:HDU-2955 Robberies:

    F:HDU-2197

    G:HDU-1114


    背包的问题可先参考视频(背包DP

    01背包模板

    #include <cstring>
    #include <iostream>
    #include <cstdio>
    #include <fstream>
    #include <algorithm>
    using namespace std;
    const int maxn=1e4+7;
    const int INF=0x3f3f3f3f;
    int value[maxn],size1[maxn],dp[maxn];  //f[x]表示背包容量为x时的最大价值
    int main()
    {
        int t;
        cin>>t;
        while(t--){
            memset(dp,0,sizeof(dp));
            int n,x;
            cin>>n>>x;    //n为物品种类,x为容量
            for(int i=1;i<=n;i++)
                cin>>value[i];
            for(int i=1;i<=n;i++)
                cin>>size1[i];
            for(int i=1;i<=n;i++)
               for(int j=x;j>=size1[i];j--)
                   dp[j]=max(dp[j],dp[j-size1[i]]+value[i]);
            cout<<dp[x]<<endl;
        }
        return 0;
    }

    多重背包模板

    #include <cstring>
    #include <iostream>
    #include <cstdio>
    #include <fstream>
    #include <algorithm>
    using namespace std;
    const int maxn=1e4+7;
    const int INF=0x3f3f3f3f;
    int value[maxn],size1[maxn],dp[maxn],bag[maxn];
    int main()
    {
        int t,nvalue,n;
        cin>>t;
        while(t--){
            memset(dp,0,sizeof(dp));
            cin>>nvalue>>n;
            for(int i=0;i<n;i++)
            cin>>value[i]>>size1[i]>>bag[i];
            for(int i=0;i<n;i++){
    
               for(int j=1;j<=bag[i];j++)
                  for(int k=nvalue;k>=value[i];k--)
                   dp[k]=max(dp[k],dp[k-value[i]]+size1[i]);
            }
            cout<<dp[nvalue]<<endl;
        }
        return 0;
    }

    完全背包模板

    #include <iostream>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <cstdio>
    #include <sstream>
    #include <cstdlib>
    #define ll long long
    using namespace std;
    const int maxn = 1e6+10;
    const int INF=0x3f3f3f3f;
    int a[600],b[600],dp[1000005];
    int main()
    {
        int t,x,y,n;
        cin>>t;
        while(t--){
            int w;
            cin>>w;   //背包容量
            cin>>n;
            for(int i=0;i<n;i++)
                cin>>a[i]>>b[i];
            for(int i=0;i<=w;i++)  //初始化分两种情况:1、如果背包要求正好装满则初始化 f[0] = 0, f[1~w]=INF;  2、如果不需要正好装满 f[0~w] = 0; 
                dp[i]=INF;
                dp[0]=0;
            for(int i=0;i<n;i++)
            for(int j=b[i];j<=w;j++){
                    dp[j]=max(dp[j],dp[j-b[i]]+a[i]);
            }
        }
        return 0;
    }

    例题

    A:HDU-2546 饭卡:n道菜,选出最贵的,放到最后买,然后在保留5元的情况下,用n-5元买剩下的才转化为背包问题。AC代码:

    #include <cstring>
    #include <iostream>
    #include <cstdio>
    #include <fstream>
    #include <algorithm>
    using namespace std;
    const int maxn=1e4+7;
    const int INF=0x3f3f3f3f;
    int value[maxn],size1[maxn],dp[maxn];
    int main()
    {
        int n;
        while(cin>>n&&n!=0){
            memset(dp,0,sizeof(dp));
            int x;
            for(int i=1;i<=n;i++)
                cin>>value[i];
            cin>>x;
            if(x<5){
                cout<<x<<endl;
                continue;
            }
            sort(value+1,value+1+n);
            for(int i=1;i<n;i++){
               for(int j=x-5;j>=value[i];j--)
                   dp[j]=max(dp[j],dp[j-value[i]]+value[i]);
            }
            cout<<x-dp[x-5]-value[n]<<endl;
        }
        return 0;
    }

    B:HDU-1171 Big Event in HDU:多重背包问题,把背包容量当作sum/2(sum为所有物品的体积和)即可,AC代码:

    #include <cstring>
    #include <iostream>
    #include <cstdio>
    #include <fstream>
    #include <algorithm>
    using namespace std;
    const int maxn=1e6+7;
    const int INF=0x3f3f3f3f;
    int value[160],size1[160],dp[maxn],bag[60];
    int main()
    {
        int sum,sum1,n;
        while(cin>>n&&n>0)
        {
            sum=0;
            memset(dp,0,sizeof(dp));
            for(int i=0; i<n; i++)
            {
                cin>>size1[i]>>bag[i];
                sum+=size1[i]*bag[i];
            }
            sum1=sum/2;
            for(int i=0; i<n; i++)
            {
    
                for(int j=0; j<bag[i]; j++)
                    for(int k=sum1; k>=size1[i]; k--)
                    {
                        dp[k]=max(dp[k],dp[k-size1[i]]+size1[i]);
                    }
            }
            cout<<sum-dp[sum1]<<' '<<dp[sum1]<<endl;
        }
        return 0;
    }

    C:HDU-2602 Bone Collector:01背包模板题,直接上代码:

    #include <cstring>
    #include <iostream>
    #include <cstdio>
    #include <fstream>
    #include <algorithm>
    using namespace std;
    const int maxn=1e4+7;
    const int INF=0x3f3f3f3f;
    int value[maxn],size1[maxn],dp[maxn];
    int main()
    {
        int t;
        cin>>t;
        while(t--){
            memset(dp,0,sizeof(dp));
            int n,x;
            cin>>n>>x;
            for(int i=1;i<=n;i++)
                cin>>value[i];
            for(int i=1;i<=n;i++)
                cin>>size1[i];
            for(int i=1;i<=n;i++)
               for(int j=x;j>=size1[i];j--)
                   dp[j]=max(dp[j],dp[j-size1[i]]+value[i]);
            cout<<dp[x]<<endl;
        }
        return 0;
    }

    D:HDU-2639 Bone Collector II:第k优解问题。这一题感觉不是很容易想到,要求背包第K大的价值。我们通俗的01背包是保留当前状态下的最好决策,比如最大或最小。但是这里要求第K大的价值,我们用单纯的01背包肯定是算不出来的,因为有一些不优的状态被我们省掉了,但是这些状态可能会被第K大的取到,所以我们要先办法保留状态。 我们这里用三个数组,cnt1,cnt2和用来DP的数组D。 cnt1[k]表示取第i件物品时,第k大的价值。 cnt2[k]表示不取第i件物品时,第k大的价值。 D[j][k]表示背包容量为j时,第k大的价值。 我们可以看到,在第i,j个状态时,我们可以用在i-1状态时的D数组推得cnt1,和cnt2。再用cnt1,2来推当前的D数组。写出来是这样的: cnt1[k]=d[j-v[i]][k]+c[i]; cnt2[k]=d[j][k]; D=cnt1和cnt2的合并。

    #include <cstring>
    #include <iostream>
    #include <cstdio>
    #include <fstream>
    #include <algorithm>
    using namespace std;
    #define max(a,b)	((a)>(b)?(a):(b))
    const int maxn = 1005;
    int main()
    {
    	int T;
    	scanf("%d", &T);
    	int dp[maxn][33], val[maxn], vol[maxn], A[33], B[33];
    	while (T--)
    	{
    		int n, v, k;
    		scanf("%d %d %d", &n, &v, &k);
    		int i, j, kk;
    		for (i=1; i<=n; i++) scanf("%d", &val[i]);
    		for (i=1; i<=n; i++) scanf("%d", &vol[i]);
    		memset(dp, 0, sizeof(dp));
     
    		int a, b, c;
    		for (i=1; i<=n; i++)
    			for (j=v; j>=vol[i]; j--)
    			{
    				for (kk=1; kk<=k; kk++)
    				{
    					A[kk] = dp[j-vol[i]][kk] + val[i];
    					B[kk] = dp[j][kk];
    				}
    				A[kk] = -1, B[kk] = -1;
    				a = b = c = 1;
    				while (c<=k && (A[a] != -1 || B[b] != -1))
    				{
    					if (A[a] > B[b])
    						dp[j][c] = A[a++];
    					else
    						dp[j][c] = B[b++];
    					if (dp[j][c] != dp[j][c-1])
    						c++;
    				}
    			}
     
    		printf("%d
    ", dp[v][k]);
    	}
    	return 0;
    }

    E:HDU-2955 Robberies:给大家推荐个非常巧的解法Robberies题解,代码:

    #include <cstring>
    #include <iostream>
    #include <cstdio>
    #include <fstream>
    #include <algorithm>
    using namespace std;
    const int maxn=1e4+7;
    const int INF=0x3f3f3f3f;
    int value[maxn];
    double size1[maxn],dp[maxn];
    int main()
    {
        int t;
        cin>>t;
        while(t--){
            double x,sum=0;
            int n;
            cin>>x>>n;
            for(int i=1;i<=n;i++){
                cin>>value[i]>>size1[i];
                sum+=value[i];
            }
            for(int i=0;i<=sum+1;i++){
    			dp[i]=0.0;
    		}
    		dp[0]=1;
            for(int i=1;i<=n;i++){
               for(int j=sum;j>=value[i];j--)
                   dp[j]=max(dp[j],dp[j-value[i]]*(1-size1[i]));
            }
            for(int i=sum;i>=0;i--){
                if((1-dp[i])<=x){
                    cout<<i<<endl;
                    break;
                }
            }
        }
        return 0;
    }

    F:HDU-2197 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活:多重背包的模板题,AC代码:

    #include <cstring>
    #include <iostream>
    #include <cstdio>
    #include <fstream>
    #include <algorithm>
    using namespace std;
    const int maxn=1e4+7;
    const int INF=0x3f3f3f3f;
    int value[maxn],size1[maxn],dp[maxn],bag[maxn];
    int main()
    {
        int t,nvalue,n;
        cin>>t;
        while(t--){
            memset(dp,0,sizeof(dp));
            cin>>nvalue>>n;
            for(int i=0;i<n;i++)
            cin>>value[i]>>size1[i]>>bag[i];
            for(int i=0;i<n;i++){
    
               for(int j=1;j<=bag[i];j++)
                  for(int k=nvalue;k>=value[i];k--)
                   dp[k]=max(dp[k],dp[k-value[i]]+size1[i]);
            }
            cout<<dp[nvalue]<<endl;
        }
        return 0;
    }

    G:HDU-1114 Piggy-Bank:完全背包的模板题,AC代码:

    #include <iostream>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <cstdio>
    #define ll long long
    using namespace std;
    const int maxn = 1e6+10;
    const int INF=0x3f3f3f3f;
    int a[600],b[600],dp[1000005];
    int main()
    {
        int t,x,y,n;
        cin>>t;
        while(t--){
            cin>>x>>y;
            cin>>n;
            for(int i=0;i<n;i++)
                cin>>a[i]>>b[i];
            int w;
            w=y-x;
            for(int i=0;i<=w;i++)
                dp[i]=INF;
                dp[0]=0;
            for(int i=0;i<n;i++)
            for(int j=b[i];j<=w;j++){
                    dp[j]=min(dp[j],dp[j-b[i]]+a[i]);
            }
            if(dp[w] == INF)
            printf("This is impossible.
    ");
            else
            printf("The minimum amount of money in the piggy-bank is %d.
    ",dp[w]);
        }
        return 0;
    }
  • 相关阅读:
    数据结构与算法系列——排序(6)_树形选择排序
    数据结构与算法系列——排序(7)_堆排序
    数据结构与算法系列——排序(5)_简单选择排序
    数据结构与算法系列——排序(4)_Shell希尔排序
    数据结构与算法系列——排序(3)_折半插入排序
    数据结构与算法系列——排序(2)_直接插入排序
    数据结构与算法系列——排序(1)_概述
    Java高级开发_性能优化的细节
    图形推理
    美团点评面试20190515
  • 原文地址:https://www.cnblogs.com/shmilky/p/14089052.html
Copyright © 2011-2022 走看看