zoukankan      html  css  js  c++  java
  • [笔记]: 背包问题 2017-06-13 11:49 37人阅读 评论(0) 收藏

    背包问题 

    关于讲解详见dd大牛的背包九讲

    我就存一下我自己写的代码吧。。有一些自己的理解

    1.01背包

    二维

    //01背包最基础版
    /*
    样例
    11 6
    2 4 5 6 10 3
    1 7 4 5 11 1	 
    */ 
    /*
    注意:
    如果一定要装满 
    则在初始化的时候f[0]=0;
    其他的f都为-inf 
    */
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define N 1000 
    using namespace std;
    int f[N][N];
    int v[N],w[N];
    int main(){
    	memset(f,0,sizeof(f));
    	int n,V;
    	scanf("%d%d",&V,&n);
    	for(int i=1;i<=n;i++)
    		scanf("%d",&w[i]);
    	for(int i=1;i<=n;i++)
    		scanf("%d",&v[i]);
    	for(int i=1;i<=n;i++)//f[i][j]代表前i件物品放入容积为j所产生的最大价值 
    		for(int j=0;j<=V;j++){
    			f[i][j]=f[i-1][j];
    			if(j>=w[i])
    			f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+v[i]);
    		}
    	for(int i=1;i<=n;i++){
    		for(int j=0;j<=V;j++)
    			printf("%d ",f[i][j]);
    		printf("
    ");
    	}
    	return 0;
    }
    一维

    //01背包一维数组
    //考虑到当前状态只和前一层有关 所以以一维数组进行优化空间复杂度 
    //唯一改变的是内层循环j改成逆序 因为当前层存的是上一层的 状态由上层转移过来 
    /*
    样例
    11 6
    2 4 5 6 10 3
    1 7 4 5 11 1	 
    */ 
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define N 1000 
    using namespace std;
    int f[N];
    int v[N],w[N];
    int main(){
    	memset(f,0,sizeof(f));
    	int n,V;
    	scanf("%d%d",&V,&n);
    	for(int i=1;i<=n;i++)
    		scanf("%d",&w[i]);
    	for(int i=1;i<=n;i++)
    		scanf("%d",&v[i]);
    	for(int i=1;i<=n;i++)//f[i][j]代表前i件物品放入容积为j所产生的最大价值 
    		for(int j=V;j>=w[i];j--)//逆序! j最小只用到w[i] 因为小于w[i]就放不下了 就是上一层的答案 
    			f[j]=max(f[j],f[j-w[i]]+v[i]);
    	for(int i=0;i<=V;i++)
    	printf("%d ",f[i]);
    	return 0;
    }

    2.完全背包

    一维

    /*
    11 6
    2 4 5 6 10 3
    1 7 4 5 11 1
    */
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #define N 1000 
    using namespace std;
    int f[N];
    int v[N],w[N];
    int main(){
    	memset(f,0,sizeof(f));
    	int n,V;
    	scanf("%d%d",&V,&n);
    	for(int i=1;i<=n;i++)
    		scanf("%d",&w[i]);
    	for(int i=1;i<=n;i++)
    		scanf("%d",&v[i]);
    	for(int i=1;i<=n;i++)
    		for(int j=w[i];j<=V;j++)
    			f[j]=max(f[j],f[j-w[i]]+v[i]); 
    	printf("%d",f[V]);
    	return 0;
    }

    二维

    /*
    11 6
    2 4 5 6 10 3
    1 7 4 5 11 1
    */
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define N 1000 
    using namespace std;
    int f[N][N];
    int v[N],w[N];
    int main(){
    	memset(f,0,sizeof(f));
    	int n,V;
    	scanf("%d%d",&V,&n);
    	for(int i=1;i<=n;i++)
    		scanf("%d",&w[i]);
    	for(int i=1;i<=n;i++)
    		scanf("%d",&v[i]);
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=V;j++)
    		{
    			f[i][j]=f[i-1][j];
    			for(int k=1;k<=j/w[i];k++){	
    				if(j>=k*w[i])
    				f[i][j]=max(f[i-1][j],f[i-1][j-k*w[i]]+k*v[i]); 
    			}
    		}
    	for(int i=1;i<=n;i++){
    		for(int j=0;j<=V;j++)
    			printf("%d ",f[i][j]);
    		printf("
    ");
    	}
    	return 0;
    }

    3.多重背包

    //http://acm.hdu.edu.cn/showproblem.php?pid=2191
    //多重背包模板题 
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    int f[1005],p[1005],h[1005],c[1005];
    int main(){
    	int T;
    	scanf("%d",&T);
    	int n,m;
    	while(T--){
    		scanf("%d%d",&n,&m);
    		for(int i=1;i<=m;i++)
    			scanf("%d%d%d",&p[i],&h[i],&c[i]);
    		for(int i=1;i<=m;i++)
    			for(int k=1;k<=c[i];k++)
    				for(int j=n;j>=p[i];j--)
    					f[j]=max(f[j],f[j-p[i]]+h[i]);
    		printf("%d
    ",f[n]);
    		memset(f,0,sizeof(f));
    	}
    	
    }
    改进版代码
    /** 此做法时间复杂度大大降低 虽然还不会 
    *  多重背包: 
    *          有N种物品和一个容量为V的背包。第i种物品最多有Mi件可用, 
    *          每件耗费的空间是Ci,价值是Wi。 
    *          求解将哪些物品装入背包可使这些物品的耗费的空间总和不超过背包容量,且价值总和最大。 
    */  
    #include <stdio.h>  
    #include <string.h>  
    int max(int a, int b){  
        if (a > b)return a;  
        return b;  
    }  
    #define maxn 100005  
    int c[maxn], w[maxn], num[maxn];//c:费用 w:价值 num:数量  
    int dp[maxn];             
    int V;               //V:容量 V1:容量2  
      
    //01背包  
    void ZeroOnePack(int c, int w)  
    {  
        for (int v = V; v >= c; v--)  
        {  
            dp[v] = max(dp[v], dp[v - c] + w);  
        }  
    }  
    //完全背包  
    void CompletePack(int c, int w)  
    {  
        for (int v = c; v <= V; v++)  
        {  
            dp[v] = max(dp[v], dp[v - c] + w);  
        }  
    }  
    //多重背包  
    void MultiplePack(int c, int w, int num)  
    {  
        if (c * num >= V)  
        {  
            CompletePack(c, w);  
        }  
        else  
        {  
            int k = 1;  
            while (k < num)  
            {  
                ZeroOnePack(k*c, k*w);  
                num -= k;  
                k <<= 1;  
            }  
            ZeroOnePack(num*c, num*w);  
        }  
    }  
    int main()  
    {  
        int t;  
        scanf("%d", &t);  
        while (t--)  
        {  
            int n;  
            scanf("%d%d", &V, &n);  
            for (int i = 1; i <= n; i++)  
                scanf("%d%d%d", &c[i], &w[i], &num[i]);  
            memset(dp, 0, sizeof(dp));  
            for (int i = 1; i <= n; i++)  
                MultiplePack(c[i], w[i], num[i]);  
            printf("%d
    ", dp[V]);  
        }  
        return 0;  
    }  
    /* 
    1 
    10 5 
    5 1 1 
    4 2 1 
    3 3 1 
    2 4 1 
    1 5 1 
    ** 
    14 
    */  


    核心代码部分

    0/1背包
      二维实现:
        for(int i=1;i<=n;i++)
         for(int j=1;j<=v;j++)
          {
            f[i][j]=f[i-1][j];
            if((j>=w[i])&&(f[i][j]<f[i-1][j-w[i]]+p[i]))f[i][j]=f[i-1][j-w[i]]+p[i];
          }
        cout<<f[n][v];
      一维实现:
        for(int i=1;i<=n;i++)
          for(int j=v;j>=w[i];j--)
            if(f[j]<f[j-w[i]]+p[i])f[j]=f[j-w[i]]+p[i];
        cout<<f[v];
    
    完全背包:
       二维实现:
           for(int i=1;i<=n;i++)
             for(int j=1;j<=v;j++)
               for(int k=0;k<=j/w[i];k++)
                  if((j>=k*w[i])&&(f[i][j]<f[i-1][j-k*w[i]]+k*p[i]))
                     f[i][j]=f[i-1][j-k*w[i]]+k*p[i];
          cout<<f[n,v];
        一维实现:
            for(int i=1;i<=n;i++)
              for(int j=1;j<=v;j++)
                for(int k=0;k<=j/w[i];k++)
                  if((j>=w[i]*k)&&(f[j]<f[j-k*w[i]]+k*p[i]))
                      f[j]=f[j-k*w[i]]+k*p[i];
          cout<<f[v];
    多重背包:
       与完全背包相似,只是决策不同,即k:=0 to n[i] do  (n[i]即第i件物品的数量)
       


  • 相关阅读:
    .NET实时2D渲染入门·动态时钟
    JAVA中抽象类的使用
    R语言中函数调试
    利用Bioperl的SeqIO模块解析fastq文件
    ASCII码表
    JAVA 中转义符的理解
    在线引物设计网站,老板推荐的,亲测好用
    列出一个买东西的好网站,值得推荐
    R语言集合操作
    R语言do.call 函数用法详解
  • 原文地址:https://www.cnblogs.com/xljxlj/p/7183616.html
Copyright © 2011-2022 走看看