zoukankan      html  css  js  c++  java
  • 【9925】0/1背包

    Time Limit: 1 second
    Memory Limit: 128 MB

    【问题描述】

    一个旅行者有一个最多能用M公斤的背包,现在有n件物品,它们的重量分别是W1,W2,...,Wn,它们的价值分别为C1,C2,...,Cn.若
    每种物品只有一件求旅行者能获得最大总价值。

    【输入格式】

    第一行:两个整数,M(背包容量,M<=200)和N(物品数量,N<=30);
    第2..N+1行:每行二个整数Wi,Ci,表示每个物品的重量和价值。

    【输出格式】

    仅一行,一个数,表示最大总价值。

    Sample Input

    10 4
    2  1
    3  3
    4  5
    7  9
    
    
    

    Sample Output

    12
    

    【法1】
    设f[i][j]表示前i个物品,装的总重量不超过j时所获得的最大价值。
    一开始初值都为0;
    f[i][j] = max{f[i-1][j],f[i-1][j-w[i]]+c[i]};其中w[i]是第i个物品的重量,c[i]是第i个物品的价值。
    f[i-1][j]表示不选第i个物品,d[i-1][j-w[i]] +c[i],表示选第i个物品。
    前i个物品装的总重量不超过j可以由前i-1个物品,总重量不超过j-w[i] 再装一个物品 得到,这时候装了一个物品就变成不超过j了。
    这是样例的模拟结果;
    在第1个物品进行选择后:f[1][0]=0 f[1][1]=0 f[1][2]=1 f[1][3]=1 f[1][4]=1 f[1][5]=1 f[1][6]=1 f[1][7]=1 f[1][8]=1 f[1][9]=1 f[1][10]=1 


    在第2个物品进行选择后:f[2][0]=0 f[2][1]=0 f[2][2]=1 f[2][3]=3 f[2][4]=3 f[2][5]=4 f[2][6]=4 f[2][7]=4 f[2][8]=4 f[2][9]=4 f[2][10]=4 


    在第3个物品进行选择后:f[3][0]=0 f[3][1]=0 f[3][2]=1 f[3][3]=3 f[3][4]=5 f[3][5]=5 f[3][6]=6 f[3][7]=8 f[3][8]=8 f[3][9]=9 f[3][10]=9 

    在第4个物品进行选择后:f[4][0]=0 f[4][1]=0 f[4][2]=1 f[4][3]=3 f[4][4]=5 f[4][5]=5 f[4][6]=6 f[4][7]=9 f[4][8]=9 f[4][9]=10 f[4][10]=12 

    【代码1】
    #include <cstdio>
    #include <cstring>
    
    int m,n,f[50][250],w[50],c[50];
    
    void input_data()
    {
    	scanf("%d%d",&m,&n);
    	for (int i = 1;i <= n;i++) //输入各个物品的信息 
    		scanf("%d%d",&w[i],&c[i]);
    }	
    
    void get_ans()
    {
    	memset(f,0,sizeof(f));
    	for (int i = 1;i <= n;i++) //枚举第i个物品 
    		for (int j = m;j >= 0;j--) //枚举所占空间 
    			{
    				f[i][j] = f[i-1][j]; //表示第i个物品不拿 
    				if (j >= w[i]) //如果第i个物品在当前所用空间情况下可以拿则尝试拿。 
    					if (f[i-1][j-w[i]] + c[i] > f[i][j])
    						f[i][j] = f[i-1][j-w[i]] + c[i];
    			}
    }
    
    void output_ans()
    {
    	printf("%d",f[n][m]);	
    }
    
    int main()
    {
    	input_data();
    	get_ans();
    	output_ans();
    	return 0;	
    }

    【法二】
    把二维换成一维的数组。
    f[j]表示使用的容量不超过j时,所获得的最大利益。
    f[j] = max{f[j],f[j-w[i]] + c[i]}
    等于f[j]表示这个物品不选,f[j-w[i]] + c[i]则表示选了一个重量为w[i]的物品。
    大家可以看一下f[j]数组的更新情况
    在对第1号背包进行抉择之后:f[0]=0 f[1]=0 f[2]=1 f[3]=1 f[4]=1 f[5]=1 f[6]=1 f[7]=1 f[8]=1 f[9]=1 f[10]=1 


    在对第2号背包进行抉择之后:f[0]=0 f[1]=0 f[2]=1 f[3]=3 f[4]=3 f[5]=4 f[6]=4 f[7]=4 f[8]=4 f[9]=4 f[10]=4 


    在对第3号背包进行抉择之后:f[0]=0 f[1]=0 f[2]=1 f[3]=3 f[4]=5 f[5]=5 f[6]=6 f[7]=8 f[8]=8 f[9]=9 f[10]=9 


    在对第4号背包进行抉择之后:f[0]=0 f[1]=0 f[2]=1 f[3]=3 f[4]=5 f[5]=5 f[6]=6 f[7]=9 f[8]=9 f[9]=10 f[10]=12 

    可以和上面的二维进行对比,会发现是一样的。也就是说,其省略了一维的数组,却得到了相同的结果。
    要注意这里的j这层循环一定要倒序
    不然,如果有一个物品的重量为1
    你更新完f[5],然后又更新f[6],又更新f[7]。。。只有一个物品。。你更新了好几次。(这个是完全背包??我不确定)
    【代码2】
    #include <cstdio>
    #include <cstring>
    
    int m,n,f[250],w[50],c[50];
    
    void input_data()
    {
    	scanf("%d%d",&m,&n);
    	for (int i = 1;i <= n;i++) //输入各个物品的信息 
    		scanf("%d%d",&w[i],&c[i]);
    }	
    
    void get_ans()
    {
    	memset(f,0,sizeof(f));
    	for (int i = 1;i <= n;i++) 
    		{
    			for (int j = m;j >= w[i];j--) //注意一定要倒序枚举,原因我在题解里面讲了。认真体会下。 
    				if (f[j-w[i]] + c[i] > f[j])
    					f[j] = f[j-w[i]] + c[i];
    		}
    				 
    }
    
    void output_ans()
    {
    	printf("%d",f[m]);	
    }
    
    int main()
    {
    	input_data();
    	get_ans();
    	output_ans();
    	return 0;	
    }


  • 相关阅读:
    Mastering Web Application Development with AngularJS 读书笔记-前记
    通过信息系统项目管理师-我的备考经验
    通过系统集成项目管理工程师考试-我的备考分享
    即将翻译 Building The New Financial Times Web App
    CSS3:flex布局应用
    前端性能利器——dynatrace ajax edition
    SIMD---AVX系列
    DirectSound---捕获音频、Qml/C++ 集成交互
    SIMD---SSE系列及效率对比
    SIMD---MMX代码优化
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7632396.html
Copyright © 2011-2022 走看看