LFYZ-OJ ID: 1028 背包问题

背包问题

题目描述

简单的背包问题。设有一个背包,可以放入的重量为s。现有n件物品,重量分别为w1,w2…,wn,(1≤i≤n)均为正整数,从n件物品中挑选若干件,使得放入背包的重量之和正好为s。找到一组解即可。

输入

第一行是物品总件数和背包的载重量,第二行为各物品的重量。

输出

各所选物品重量。

样例输入

5 10
1 2 3 4 5

样例输出

number:1 weight:1
number:4 weight:4
number:5 weight:5

分析

  • 背包问题是最经典的算法问题之一。当数据量很小时,使用枚举法把所有情况测试一遍即可解决,然而当数据量很大时,这种方法就无可行性,需要使用到二叉树结构和动态规划等进行解决,这在以后的学习中会讲到。在这里因为数据量很小,我们仍然考虑最简单的方法:枚举。

  • 这样枚举:有n件商品,每件商品可以选择装或者不装,那就有2X2X2X...X2=2n种情况。你知道为什么n很大的时候就不能枚举了吧?指数级的时间复杂度时很可怕的!

  • 该如何编程实现上面的枚举方法?这其实也是n个物品的组合问题。这里提供一个递归的思路。函数bool search(int itemNum, int space)有两个参数,第一个参数是物品编号,第二个参数是背包的空间大小。

    • 递归的终止条件1:space<0----->return false;(超重)
    • 递归的终止条件2:space==0---->return true;(刚好装满)
    • 递归的终止条件3:itemNum==0-->return false;(没有物品了)
    • 递归方法
      • search(itemNum-1, space-item[itemNum])装上物品itemNum,尝试装物品itemNum-1
      • search(itemNum-1, space)不装物品itemNum,尝试装物品itemNum-1

递归过程中itemNum从n递归到1,这是因为输出格式中物品号码小的在前、大的在后,按照递归的顺序,后入栈的先出栈,也就是后装的先输出,所以枚举过程中先枚举编号大的物品,最后枚举编号小的物品,使得输出时先输出编号小的物品。需要注意的是,满足情况的装载情况不只有一种,例程在找到一种方案后即返回,不会把所有的方案找出来。你可以自己尝试一下,把所有的装载情况列举出来!

例程

#include<iostream>
using namespace std;
int n, item[1000];                                      //item数组存储物品的重量
int s;
bool search(int itemNum, int space){
	if(space==0)					return true;        //终止条件
	if(space<0 || itemNum==0)		return false;       //终止条件
	if(search(itemNum-1, space-item[itemNum])){         //装物品itemNum,尝试装物品itemNum-1,成功返回true
		cout<<"number:"<<itemNum<<"  weight:"<<item[itemNum]<<endl;
		return true;
	}
	if(search(itemNum-1, space)){                       //不装物品itemNum,尝试装物品itemNum-1,成功返回true
		return true;
	}
	return false;
}
int main(){
	cin>>n>>s;
	for(int i=1; i<=n; i++)	cin>>item[i];
	if(!search(n, s))                                   //返回false代表没有找到合适的方案
		cout<<"not found";
	return 0;
}
posted @ 2017-05-25 11:45  LFYZOI题解  阅读(1101)  评论(0编辑  收藏  举报