首页 > 试题广场 >

“背包题目”的基本描述是:有一个背包,能盛放的物品总重量为S

[问答题]
“背包题目”的基本描述是:有一个背包,能盛放的物品总重量为S,设有N件物品,其重量分别为w1,w2,…,wn,希望从N件物品中选择若干物品,所选物品的重量之和恰能放进该背包,即所选物品的重量之和即是S。递归和非递归解法都能求得“背包题目”的一组解,试写出“背包题目”的非递归解法
推荐
  1. // ---------------------------------------------------   
  2. //  注1: 一般要求一个解,此程序是得到所有解   
  3. //  注2: 由于32位unsigned int限制,最多32个物品                           
  4. // ---------------------------------------------------   
  5.   
  6. #include "stdafx.h"   
  7. #include <iostream>   
  8. using   namespace  std;  
  9.   
  10. // 物品总数   
  11. const   int  N_ITEM = 5;  
  12.   
  13. // 背包能装的重量   
  14. const   int  BAG = 15;  
  15.   
  16. // 初始化每个物品的重量   
  17. int  item[N_ITEM] = {2, 3, 5, 7, 8};  
  18.   
  19. // 标记数组   
  20. int  flag[N_ITEM] = {0, 0, 0, 0, 0};  
  21.   
  22. // 结果计数器   
  23. int  resultCount = 0;  
  24.   
  25. // 打印结果   
  26. void  Print();  
  27.   
  28. int  main()  
  29. {  
  30.     // 打印已知条件   
  31.     cout << "BAG Weight:"  << BAG << endl;  
  32.     cout << "Item Number:"  << N_ITEM << endl;  
  33.   
  34.     for  ( int  i=0; i!=N_ITEM; i++)  
  35.     {  
  36.         cout << "Item."  << i+1 <<  " W="  << item[i] <<  "\t" ;  
  37.     }  
  38.   
  39.     cout << endl;  
  40.   
  41.     unsigned int  count = 0;  
  42.     unsigned int  all_count = 1;  
  43.   
  44.     for  ( int  i=0; i!=N_ITEM; i++)  
  45.     {  
  46.         all_count *= 2;//all_count记录可能解的个数   
  47.     }  
  48.   
  49.     while  (1)  
  50.     {  
  51.         // 模拟递归...列举所有flag数组可能   
  52.         // 其实就这个for循环是关键   
  53.         for  ( int  i=0; i!=N_ITEM; i++)  
  54.         {  
  55.             if  ( 0 == flag[i] )  
  56.             {  
  57.                 flag[i] = 1;  
  58.                 continue ;  
  59.             }             
  60.             else    
  61.             {  
  62.                 flag[i] = 0;  
  63.                 break ;  
  64.             }  
  65.         }  
  66.           
  67.         // 本次重量,初始化0   
  68.         int  temp = 0;  
  69.   
  70.         // 按标记计算所有选中物品重量和   
  71.         for  ( int  i=0; i!=N_ITEM; i++)  
  72.         {  
  73.             if  ( 1 == flag[i] )  
  74.             {  
  75.                 temp += item[i];  
  76.             }  
  77.         }  
  78.   
  79.         // 满足背包重量就打印   
  80.         if  ( temp == BAG )  
  81.         {  
  82.             resultCount++;  
  83.             Print();  
  84.         }         
  85.   
  86.         // 如果遍历了所有情况就break掉while(1)循环   
  87.         count++;  
  88.         if  (count == all_count)  
  89.         {  
  90.             break ;  
  91.         }  
  92.     }  
  93.   
  94.     return  0;  
  95. }  
  96.   
  97. void  Print()  
  98. {  
  99.     cout << "Result "  << resultCount << endl;  
  100.   
  101.     for  ( int  i=0; i!=N_ITEM; i++)  
  102.     {  
  103.         if  ( 1 == flag[i] )  
  104.         {  
  105.             cout << "Item."  << i+1 <<  "  Weight:"  << item[i] <<  "\t" ;  
  106.         }  
  107.     }  
  108.   
  109.     cout << endl;  
  110. }  
编辑于 2015-01-06 17:19:30 回复(3)

动态规划求一组解,我们用f[i][j]用来表示前i件物品随意选择一些物品能够恰好装满容量为j的背包的可行性=1,不可行则为0;如果j < v[i]:f[i][j] = f[i-1][j] ,表示第i个物品的重量已经超过最大重量j了,则结果变为了前i-1件物品能否恰好装入容量为j的背包的可行性即等于f[i-1][j];

如果j>=v[i],此时就可以选择装或者不装第i件物品了,如果装入,则它的可行性就变为了前i-1前物品是否能恰好装入j-vec[i]容量的背包中可行性了;选择不装,则它的可行性变为了前i-1物品能否恰好装入容量为j的背包中可行性了,两者有一个可行,表明前i件物品就能恰好装入容量为j的背包中。f[i][j] = f[i-1][j]||f[i-1][j-vec[i]]

初始化:f[i][0]=1(i=0,1,2,,..n) 其它的f[i][j]都等于0

找出最终的一组解,用回溯就可以了。如果存在可行解,那么f[n][S]一定为1
void packageInteration(vector<int> vec, int S){
    int n = vec.size();
    int **f = new int*[n+1];
    for(int i = 0; i < n+1; i++){
        f[i] = new int[S+1];
        memset(f[i], 0, sizeof(f[i])*(S+1));
    }
    for(int i = 0; i < n+1; i++)
        f[i][0] = 1;   // 初始化
    for(int i = 1; i < n+1; i++){
        for(int j = 1; j < S+1; j++){
            if(j >= vec[i-1])
                f[i][j] = (f[i-1][j] || f[i-1][j-vec[i-1]]);
            else
                 f[i][j] = f[i-1][j];
        }    
    }
    // 回溯求结果
    int j = S;
    for(int i = n; i > 0; i--){
        if(j >= vec[i-1]){
            if(f[i][j-vec[i-1]] == 1){   // 为1 表示可行
                res.push_back(i);
                j = j - vec[i-1];
            }
        }
    }
}

编辑于 2015-09-01 20:35:17 回复(5)
方法一:0-1背包问题
问题可以抽象如下:
给定由n个不同正数组成的数组W=(W1,W2,W3,…Wn)和一个正数S,设计一个空间复杂度为O(nS)的动态规划算法,判断是否存在满足如下条件的数组:
⑴ 该集合属于W 的子集。
⑵ 该集合中所有元素之合等于正数S 。
可以把它当成是0-1背包问题:数组元素当成是物品,物品的价值与重量是元素的值,背包的容量是S;
上代码:
	/**
	 * 将子集和问题转化为0-1背包问题
	 * dp[i][j]的含义:承重为j的背包中的前i个物品中最有价值子集的总价值
	 * 递推关系:
	 * j-arr[i]>=0,dp[i][j] = max{dp[i-1][j],arr[i] + dp[i-1][j-arr[i]]};
	 * j-arr[i]< 0,dp[i][j] = dp[i-1][j]。
	 */
	public LinkedList<Integer> SubSetSum2(int[] arr, int s) {
		LinkedList<Integer> res = new LinkedList<Integer>();
		if (arr == null || arr.length == 0 || s < 0)
			return res;
		int dp[][] = new int[arr.length+1][s + 1];
		// 计算第一行:当背包中没有物品时,总价值为0,这一步可通过dp初始化时默认为0来完成。
		// 计算其他行
		int i,j;
		for (i = 1; i < arr.length+1; i++) {
			for (j = 0; j < s+1; j++) {
				if(j-arr[i-1]>=0){
					dp[i][j] = Math.max(dp[i-1][j],arr[i-1] + dp[i-1][j-arr[i-1]]);
				}else{
					dp[i][j] = dp[i-1][j];
				}
			}
		}
		if(dp[arr.length][s]<s)
			return res;// 表示不存在和为s的子集
		// 通过回溯动态规划表,找出和为s的一个子集
		i = arr.length;
		j = s;
		while (j >= 0 && i >= 1) {
			if (dp[i][j]>dp[i - 1][j]) {
				res.addFirst(arr[i-1]);
				j -= arr[i-1];
			}
			i--;
		}
		return res;
	}
方法二:简化动态规划递推公式的含义,dp[i][j]表示 是否存在arr[0...i-1]的子集,使得子集和为j。
	/**
	 * dp[i][j]的含义:
	 * 1.是否存在arr[0...i-1]的子集,使得子集和为j,若存在为true,不存为false。
	 * 2.当dp[i-1][j]为true时,dp[i][j]以及dp[i][j+arr[i]]必然也为true(当然,j+arr[i]不能越界)。
	 */
	public LinkedList<Integer> SubSetSum(int[] arr, int s) {
		LinkedList<Integer> res = new LinkedList<Integer>();
		if (arr == null || arr.length == 0 || s < 0)
			return res;
		boolean dp[][] = new boolean[arr.length][s + 1];
		int i, j;
		// 构造第一行
		for (i = 0; i < s + 1; i++) {
			if (i == arr[0])
				dp[0][i] = true;
			dp[0][0] = true;
		}
		// 构造其他行
		for (i = 1; i < arr.length; i++) {
			for (j = 0; j < s + 1; j++) {
				if (dp[i - 1][j]) {
					dp[i][j] = true;
					if (j + arr[i] <= s)
						dp[i][j + arr[i]] = true;
				}
			}
		}
		if(!dp[arr.length-1][s])// 表示不存在和为s的子集,直接返回
			return res;
		// 通过回溯动态规划表,找出和为s的一个子集
		i = arr.length - 1;
		j = s;
		while (j >= 0 && i >= 1) {
			if (!(dp[i][j] && dp[i - 1][j])) {
				res.addFirst(arr[i]);
				j -= arr[i];
			}
			i--;
		}
		if (j == arr[0])
			res.addFirst(arr[i]);
		return res;
	}

编辑于 2015-09-01 21:02:43 回复(3)
    
        看了上面网友们的回答,我受益匪浅,这里说说我的个人想法: 1、直接采用穷举法进行求解算法复杂度太高,O(2^n),给10个输入就有些吃不消;2、用动态规划的思想,先求满足条件的种类数,然后再构造一个解。后者的时间复杂度为N*W,是非常不错的一种解法。但就我个人而言,由题目要求的“给出一组解”想到要先求“满足条件的种类数”,实在是超出了我的脑容量,我下面将给出容易想到的一种思路,并附上java代码:
        假设F[i][j]表示从前i件物品中选择一些物品将空间容量为j的背包装满的可行性,F[i][j]=1表示至少存在这样的一组物品,而F[i][j]=0表示不存在这样的一组物品。那么可以得到如下等式: 
       上述等式可以这样理解:如果第i件物品的体积v[i]大于j,那么这件物品明显不能装进背包中,所以F[i][j]= F[i-1][j]。反之,当j大于等于v[i]时,有两种选择,要么不装i,这时为 F[i-1][j],要么装i,这时为 F[i-1][j-v[i]]。另外需要补充两点:第一,初始化时F[0][0]=1,表示将0件物品装入空间大小为0的包,这个是为1而不是为0;第二,如何给出满足条件的一组解:根据上面给出的F[i][j]的等式,判决条件为:j>=v[i-1] && F[i][j]==F[i-1][j-v[i-1]]。具体原因请自行分析(提示:此时F[i][j]=true)。

Java代码如下:

/*
* 如果存在这样的一组解,则返回包含各重量值的数组,否则返回数组长度为1的数组,其值为-1。
 */
public static int[] returnValuesAddToVolume(int[] values,int volume)
	{
		boolean[][] stat = new boolean[values.length+1][volume+1];
		stat[0][0]=true;//stat[][]就是上面的F[][]
		for(int i=1;i<values.length+1;i++)
		{
			for(int j=0;j<volume+1;j++)
			{
				if(j<values[i-1])
				{
					stat[i][j]=stat[i-1][j];
				}
				else
				{
					stat[i][j]=stat[i-1][j] || stat[i-1][j-values[i-1]];
				}
			}
		}
		if(stat[stat.length-1][stat[0].length-1])//这表示有解
		{
			int i = values.length;
			int j = volume;
			List<Integer> list = new ArrayList<Integer>();
			while(i>0 && j>0)
			{
				if(j>=values[i-1] && stat[i][j]==stat[i-1][j-values[i-1]])
				{
					list.add(values[i-1]);
					j=j-values[i-1];
				}
				i--;
			}
			Integer[] temp = list.toArray(new Integer[list.size()]);
			int[] result = new int[temp.length];
			for(int k=0;k<result.length;k++)
			{
				result[k]=temp[k].intValue();
			}
			return result;
		}
		else
		{
			int[] result = {-1};
			return result;
		}
	}
编辑于 2015-08-30 11:25:54 回复(0)
算法复杂度O(N*W)
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>

#define MAX_OBJS   10
#define MAX_WEIGHT 40

int obj_weight[MAX_OBJS] = {3, 9,  10, 1,  3, 4,  8, 12, 11, 22};
int obj_value[MAX_OBJS] =  {8, 11, 23, 19, 1, 44, 2, 4,  1,  23};

int v_array[MAX_OBJS+1][MAX_WEIGHT+1];
int r_array[MAX_OBJS+1][MAX_WEIGHT+1];

int find_solution_none_recursive(int n, int w)
{
    int i, j;
    int nSolution1 = 0;
    int nSolution2 = 0;

    for (i = 1; i <= n; i++)
    {
        for (j = 1; j <= w; j++)
        {
            nSolution1 = 0;
            nSolution2 = 0;

            if (obj_weight[i-1] <= j)
            {
                nSolution1 = v_array[i-1][j-obj_weight[i-1]] + obj_value[i-1];
            }
            nSolution2 = v_array[i-1][j];

            if (nSolution1 > nSolution2)
            {
                r_array[i][j] = 1;
                v_array[i][j] = nSolution1;
            }
            else
            {
                v_array[i][j] = nSolution2;
            }
        }
    }

    return v_array[n][w];
}

void print_solution(int n, int w)
{
    if (n < 0)
    {
        return;
    }

    if (r_array[n][w] == 1)
    {
        print_solution(n-1, w-obj_weight[n-1]);
        printf("obj[%d]: weight: %-20d value: %-20d\n", n, obj_weight[n-1], obj_value[n-1]);
    }
    else
    {
        print_solution(n-1, w);
    }
}

void main(void)
{
    int max_v = 0;
    memset(r_array, 0, sizeof(r_array));
    memset(v_array, 0, sizeof(v_array));

    //max_v = find_solution_recursive(MAX_OBJS, MAX_WEIGHT);

    max_v = find_solution_none_recursive(MAX_OBJS, MAX_WEIGHT);
    printf ("max_v = %d\n", max_v);
    print_solution(MAX_OBJS, MAX_WEIGHT);
}



发表于 2015-04-09 17:21:38 回复(0)
首先物体重量从小到大排序,排好序后,我们在从重量大的物体开始,选择装入背包或不装。
递归表示;
int *dataMark = (int*)malloc(sizeof(int)*n);
初始化dataMark数据全部为0;
length = n - 1;
Choose(int *p, int length, int S)
{
    if(length < 0 || S < 0) return false;
    if(*(p+length) == S) return true;
        *(dataMark+length) = 1;
    if(Choose(p, length - 1, S - *(p+length))){
        *(dataMark+length) = 1;
        return true;
    }
    if(Choose(p, length - 1, S)))
        return true;
 }

发表于 2015-08-06 22:28:16 回复(0)
#include <iostream>
using namespace std;
int main()
{
    int k = 1, a[1000], b[1000], w, p, price[1000], weight[1000], m, c, i, j, v = 0;
    cout << "请输入物品个数" << endl;
    cin >> m;
    cout << "请输入背包总容量" << endl;
    cin >> c;
    cout << "请输入每个物品的重量" << endl;
    for ( i = 1; i <= m; i++ )
        cin >> weight[i];
    cout << "请输入每个物品的价值" << endl;
    for ( i = 1; i <= m; i++ )
        cin >> price[i];
    for ( i = 0; i <= m; i++ )
        a[i] = 0;
    while ( k >= 1 )
    {
        a[k] += 1;

        if ( a[k] <= 2 && k == m )
        {
            w   = 0;
            p   = 0;
            for ( i = 1; i <= m; i++ )
            {
                if ( a[i] == 1 )
                {
                    w   = w + weight[i];
                    p   = p + price[i];
                }
            }
            if ( w <= c && p > v )
            {
                v = p;
                for ( j = 1; j <= m; j++ )
                {
                    if ( a[j] == 2 )
                    {
                        b[j] = 0;
                    }else  {
                        b[j] = a[j];
                    }
                }
            }
        }
        if ( a[k] <= 2 && k < m )
            k++;
        else{
            a[k] = 0;
            k--;
        }
    }
    cout << endl;
    cout << "应放入";
    for ( i = 1; i < m; ++i )
        if ( b[i] == 1 )
            cout << i << ",";
    cout << b[m];
    cout << "号物品" << endl;
    cout << "最大价值为" << v << endl;
    system( "pause" );
    return(0);
}
发表于 2014-10-25 00:25:54 回复(3)
先由大到小排序,然后得到W1..+..=S的集合

发表于 2014-12-24 23:06:27 回复(0)
#include <bits> using namespace std; int main(){ int n; cin>>n; vector<int> vI; int tmp; for(int i=0;i<n>>tmp; vI.push_back(tmp); } int S; cin>>S; bool* visited = new bool[n]; memset(visited,0,n); int count = 0; int totalCount = 1; for(int i=0;i</n></int></bits>
发表于 2019-04-05 10:52:52 回复(0)
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
#define MAXN  20
#define MAXW   100
void Backage(int W[],int n,int MaxS){
    bool dp[MAXN][MAXW]; //标记选中k件物品的重量为s是否存在
    memset(&(dp[0][0]),0,sizeof(dp));
    for(int i=1;i<=n;i++){
        for(int j=i;j>=1;j--){
            for(int s=1;s<=MAXS;s++){
                if(s>=W[j-1]&&dp[i][s-S[j-1]])
                     dp[i][j]=true;
            }
        }
    }
    
}
int main(){


    return 0;
}

发表于 2016-07-13 22:32:05 回复(0)
#include<iostream> using namespace std; int f[1000], w[1000], v[1000];
int pre[1000];
void PrtSolution(int i ) {
    int j = i;
    while(j!=0) {
         cout<<j - pre[j] << " ";
         j = pre[j];
    }
} int main() {  cin>>S;
    f[0] = 1;
    for(int i = 1;i<=0;i++) 
        for(int i = S; i>=w[i]; i--) {
            if(f[i - w[i]] == 1) {
                    f[i] = 1;
                    pre[i] = i-w[i];
         }      
    if(f[i] == 1) {
          PrtSolution(i);
    }
} 
    
发表于 2016-04-03 16:14:58 回复(0)
//腾讯2014研发笔试题
/*
“背包题目”的基本描述是:有一个背包,能盛放的物品总重量为S,设有N件物品,其重量分别为w1,w2,…,wn,希望从N件物品中选择若干物品,所选物品的重量之和恰能放进该背包,即所选物品的重量之和即是S。递归和非递归解法都能求得“背包题目”的一组解,试写出“背包题目”的非递归解法
*/

#include<iostream>
#include<math.h>
using namespace std;

#define GOODS_QUANTITY 4
#define BAG_ALLOWABLE_WEIGHT 7

//背包类
class BAG
{
public:
	BAG(int allowable_weight)
	{
		this->allowable_weight=allowable_weight;
	}

	int get_allowable_weight()
	{
		return allowable_weight;
	}

	void print_allowable_weight()
	{
		cout<<"allowable weight of bag: "<<allowable_weight<<endl;
	}

private:
	int allowable_weight;
};

//物品类
class GOODS
{
public:
	GOODS(int weight)
	{
		this->weight=weight;
	}

	GOODS()
	{
		weight=0;	
	}

	void set_weight(int weight)
	{
		this->weight=weight;
	}

	int get_weight()
	{
		return weight;
	}

	void print_weight()
	{
		cout<<weight<<' ';
	}	

private:
	int weight;
};

//打印解
void print_answer(BAG &bag,GOODS *goods_ptr,int goods_quantity);

int main()
{
	int i;	
	
	//初始化测试用例
	BAG bag(BAG_ALLOWABLE_WEIGHT);
	bag.print_allowable_weight();	
	GOODS goods_set[GOODS_QUANTITY];
	cout<<"goods weight: "<<endl;
	for(i=1;i<=GOODS_QUANTITY;i++)
	{
		goods_set[i-1].set_weight(i);
		goods_set[i-1].print_weight();
	}
	cout<<endl;
	
	//计算结果
	print_answer(bag,goods_set,GOODS_QUANTITY);

	return 0;
}

void print_answer(BAG &bag,GOODS *goods_ptr,int goods_quantity)
{
	int i,j;
	int sum;
	bool mask[goods_quantity];

	for(i=0;i<goods_quantity;i++)
	{
		mask[i]=false;
	}

	cout<<"answer:"<<endl;

	//模拟二进制数递增过程,并以mask数组为掩码获得所有组合并判断是否为解
	for(i=0;i<pow(2,goods_quantity)-1;i++)
	{
		//生成一组掩码		
		j=0;
		while(j<goods_quantity)
		{
			if(mask[j]==true)
				mask[j]=false;
			else
			{
				mask[j]=true;
				break;
			}
			j++;
		}

		//使用掩码取得一组组合并求出质量之和
		sum=0;
		for(j=0;j<goods_quantity;j++)
		{
			if(mask[j]==true)
			{
				sum+=(goods_ptr+j)->get_weight();
			}
		}

		//为解则打印出结果
		if(sum==bag.get_allowable_weight())
		{
			for(j=0;j<goods_quantity;j++)
			{
				if(mask[j]==true)
				{
					(goods_ptr+j)->print_weight();
				}
			}
			cout<<endl;
		}
	}
}


发表于 2015-09-13 14:10:12 回复(0)
<pre class="prettyprint lang-cpp"> </pre> <div> #include&lt;stdio.h&gt; </div> <div> int FindNumber(int *a,int n,int w,int *MIXED) </div> <div> { </div> <div> int sum=a[0]; </div> <div> int first=a[0] </div> <div> int i,K; </div> <div> int rest; </div> <div> &nbsp; for(i=1;i&lt;n;i++) </div> <div> &nbsp; &nbsp; { </div> <div> &nbsp; &nbsp; &nbsp;&nbsp;sum +=a[i];&nbsp; </div> <div> &nbsp; &nbsp; } </div> <div> &nbsp; &nbsp;if(sum&lt;w) </div> <div> &nbsp; &nbsp; &nbsp; printf("Can't find any number that add is w!"); </div> <div> &nbsp; &nbsp;else if(sum==w) </div> <div> &nbsp; &nbsp; { </div> <div> &nbsp; &nbsp; printf("all data is the answer!"); </div> <div> &nbsp; &nbsp; for(i=0;i&lt;n;i++) </div> <div> &nbsp; &nbsp; printf("%d ",a[i]); </div> <div> &nbsp; &nbsp;&nbsp;} </div> <div> &nbsp; &nbsp; else &nbsp;//需要在数组中挑选数字进行匹配是否等于书包的最大质量s,这是这个题的重点。 </div> <div> &nbsp; &nbsp;{ </div> <div> &nbsp; &nbsp; &nbsp; for(i=0;i&lt;n;i++) </div> <div> &nbsp; &nbsp; &nbsp;{ </div> <div> &nbsp; &nbsp; &nbsp; rest=w-first; </div> <div> &nbsp; &nbsp; &nbsp; if(rest&gt;0)<br /> &nbsp; &nbsp; &nbsp;{ </div> <div> &nbsp; &nbsp; &nbsp;MIXED[k++]=first; </div> <div> &nbsp; &nbsp; &nbsp;first++; </div> <div> &nbsp; &nbsp; &nbsp;} </div> <div> &nbsp; &nbsp; &nbsp;} </div> <div> &nbsp; &nbsp; } </div> <div> return k; </div> <div> } </div> <div> int main() </div> <div> { </div> <div> int i,l; </div> <div> int weight=s; </div> <div> int length; </div> <div> int array[N]={w1,w2,w3....wn}; </div> <div> int mixed[]={}; </div> <div> length=sizeof(array)/sizeof(array[0]); </div> <div> int l=FindNumber(array,length,weight,mixed); </div> <div> for(i=0;i&lt;l;i++) </div> <div> { </div> <div> printf("%d\n",mixed(l)); </div> <div> } </div> <div> return 0; </div> <div> } </div>
发表于 2015-09-06 12:20:19 回复(0)
<p> #include&lt;iostream&gt;<br /> using namespace std; </p> <p> float w[100],p[100];<br /> bool&nbsp; x[100]; </p> <p> struct node<br /> {<br /> &nbsp;int i;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //i是结点所在的层次,表示处理的是第i件物品<br /> &nbsp;int flag;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //变量flag存储物品的取舍情况,flag为1表示选取该物品,flag为0表示不选取该物品<br /> &nbsp;int par;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //为了能方便方案,用线性的数组队,每次扩展都记录活结点的父结点下标par<br /> &nbsp;float cw;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //当前重量cw<br /> }; </p> <p> struct node enode,node,q[100];&nbsp;&nbsp; //enode为当前扩展结点,node为enode的子结点 </p> <p> void bag(int n,float m)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //返回背包最优装载的收益<br /> {<br /> &nbsp;<br /> &nbsp;int f=0,e=0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //队首、队尾指针<br /> &nbsp;int flag=0;<br /> &nbsp;//float bestp=0;<br /> &nbsp;int beste=0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //记录当前最大利润的最后一个物品的编号beste<br /> &nbsp;<br /> &nbsp;enode.cw=0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //初始化第一层<br /> &nbsp;//enode.cp=0;<br /> &nbsp;enode.i=0;<br /> &nbsp;enode.flag=0;<br /> &nbsp;enode.par=0;<br /> &nbsp;e++;<br /> &nbsp;f++;<br /> &nbsp;q[e]=enode;<br /> &nbsp;<br /> &nbsp;while(q[f].i&lt;n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //e=0子集空间树搜索完毕<br /> &nbsp;{<br /> &nbsp;&nbsp;<br /> &nbsp;&nbsp;node.cw=enode.cw+w[enode.i+1];&nbsp;&nbsp;&nbsp; //检查左孩子<br /> &nbsp;&nbsp;if(node.cw&lt;=m)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //可行的左孩子,取物品i<br /> &nbsp;&nbsp;{<br /> &nbsp;&nbsp;&nbsp;<br /> &nbsp;&nbsp;&nbsp;if(node.cw==m)<br /> &nbsp;&nbsp;&nbsp;{<br /> &nbsp;&nbsp;&nbsp;&nbsp;beste=e+1;<br /> &nbsp;&nbsp;&nbsp;&nbsp;flag=1;<br /> &nbsp;&nbsp;&nbsp;}<br /> &nbsp;&nbsp;&nbsp;<br /> &nbsp;&nbsp;&nbsp;node.flag=1;<br /> &nbsp;&nbsp;&nbsp;node.par=f;<br /> &nbsp;&nbsp;&nbsp;node.i=enode.i+1;<br /> &nbsp;&nbsp;&nbsp;e++;<br /> &nbsp;&nbsp;&nbsp;q[e]=node;<br /> &nbsp;&nbsp;}<br /> &nbsp;&nbsp;<br /> &nbsp;&nbsp;node.cw=enode.cw;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //搜索右孩子,不取物品i<br /> &nbsp;&nbsp;node.flag=0;<br /> &nbsp;&nbsp;node.par=f;<br /> &nbsp;&nbsp;node.i=enode.i+1;<br /> &nbsp;&nbsp;e++;<br /> &nbsp;&nbsp;q[e]=node;<br /> &nbsp;&nbsp;<br /> &nbsp;&nbsp;f++;<br /> &nbsp;&nbsp;enode=q[f];&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //取下一个E-结点<br /> &nbsp;}<br /> &nbsp;<br /> &nbsp;int j;<br /> &nbsp;<br /> &nbsp;<br /> &nbsp;if(flag==0)<br /> &nbsp;{<br /> &nbsp;&nbsp;cout&lt;&lt;"no."&lt;&lt;endl;<br /> &nbsp;&nbsp;return;<br /> &nbsp;}<br /> &nbsp;<br /> &nbsp;for(j=1;j&lt;=n;j++)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //输出方案之一<br /> &nbsp;{<br /> &nbsp;&nbsp;if(q[beste].flag==1)<br /> &nbsp;&nbsp;&nbsp;x[q[beste].i]=1;<br /> &nbsp;&nbsp;beste=q[beste].par;&nbsp;<br /> &nbsp;}<br /> &nbsp;for(j=1;j&lt;=n;j++)<br /> &nbsp;{<br /> &nbsp;&nbsp;if(x[j]==1)<br /> &nbsp;&nbsp;&nbsp;cout&lt;&lt;"choose "&lt;&lt;j&lt;&lt;endl;<br /> &nbsp;}<br /> } </p> <p> void main()<br /> {<br /> &nbsp;int m,n,s=0,i;<br /> &nbsp;cout&lt;&lt;"input the capacity of the bag and the number of the goods:";<br /> &nbsp;cin&gt;&gt;m&gt;&gt;n;<br /> &nbsp;<br /> &nbsp;if((m==0)||(n==0))<br /> &nbsp;{<br /> &nbsp;&nbsp;cout&lt;&lt;"no."&lt;&lt;endl;<br /> &nbsp;&nbsp;return;<br /> &nbsp;}<br /> &nbsp;cout&lt;&lt;"input the weight of the bag:"&lt;&lt;endl;<br /> &nbsp;<br /> &nbsp;<br /> &nbsp;<br /> &nbsp;for(i=1;i&lt;=n;i++)<br /> &nbsp;{<br /> &nbsp;&nbsp;cin&gt;&gt;w[i];<br /> &nbsp;&nbsp;s=s+w[i];<br /> &nbsp;&nbsp;x[i]=0;<br /> &nbsp;}<br /> &nbsp;<br /> &nbsp;if(s&lt;m)<br /> &nbsp;{<br /> &nbsp;&nbsp;cout&lt;&lt;"no."&lt;&lt;endl;<br /> &nbsp;&nbsp;return;<br /> &nbsp;}<br /> &nbsp;else if(s==m)<br /> &nbsp;{<br /> &nbsp;&nbsp;cout&lt;&lt;"whole choose."&lt;&lt;endl;<br /> &nbsp;}&nbsp;<br /> &nbsp;bag(n,m);<br /> } </p>
发表于 2015-09-05 17:03:06 回复(0)
/*
问题的解决方案:
DP: bool flag[N][S]表示包含前N个物品中的若干个,背包重量为S的可行性
	则 flag[N+1][S] = flag[N][S] || flag[N][S-w[N+1]];
	再用一个chosen来标记是否有物品被选中
*/

bool Packing(int S, int *w, int N, int *resset, int& resLen) {
	resLen = 0;
	bool ret = false;
	bool **flag = new bool*[N];
	bool **chosen = new bool*[N];
	for (int i = 0; i < N; i++) {
		flag[i] = new bool[S + 1];
		chosen[i] = new bool[S + 1];
	}
	flag[0][0] = true;
	for (int s = 1; s <= S; s++)
		flag[0][s] = (s == w[0]);
	for (int n = 1; n < N; n++) {
		flag[n][0] = true;
		for (int s = 1; s <= S; s++) {
			if (s >= w[n]) {
				if (flag[n - 1][s - w[n]]) {
					flag[n][s] = true;
					chosen[n][s] = true;
				}
				else {
					flag[n][s] = flag[n - 1][s];
					chosen[n][s] = false;
				}
			}
			else {
				flag[n][s] = flag[n - 1][s];
				chosen[n][s] = false;
			}
		}
	}
	for (int n = 0; n < N; n++) {
		if (flag[n][S]) ret = true;
	}
	if (ret) {
		int left = S;
		int leftN = N - 1;
		while (left > 0) {
			for (int n = leftN; n >= 0; n--) {
				if (chosen[n][left]) {
					left -= w[n];
					leftN = n - 1;
					resset[resLen++] = n;
					break;
				}
			}
		}
	}
	for (int i = 0; i < N; i++) {
		delete[] flag[i];
		delete[] chosen[i];
	}
	delete[] flag;
	delete[] chosen;
	return ret;
}

发表于 2015-09-04 22:41:01 回复(0)
<div> <span style="color:#333333;">非递归解法:将重量</span><span style="color:#333333;">w1,w2,…,wn按重量从小到大排序,为W1、W2、...Wn,然后采用动态规划进行求解。</span> </div> <div> <span style="color:#333333;">递归的方法:先取n个重量的组合,比较重量是否相等;不相等的话取n-1个重量的组合,比较重量...然后一直到取得对应组合数的和恰好为S;</span> </div>
发表于 2015-09-04 11:12:13 回复(0)
        感谢牛客590698号提供了参考,我copy并补充一些,用动态规划的思想,先求满足条件的种类数,然后再构造一个解。时间复杂度为N*W,
        假设F[i][j]表示从前i件物品中选择一些物品将空间容量为j的背包装满的可行性,F[i][j]=ture表示至少存在这样的一组物品,而F[i][j]=false表示不存在这样的一组物品。那么可以得到如下等式: 
       上述等式理解:如果第i件物品的体积v[i]大于j,那么这件物品明显不能装进背包中,所以F[i][j]= F[i-1][j]。反之,当j大于等于v[i]时,有两种选择,要么不装i,这时为 F[i-1][j],要么装i,这时为 F[i-1][j-v[i]]。
      另外需要补充两点:第一,初始化时F[0][0]=1,表示将0件物品装入空间大小为0的包,这个是为1而不是为0;第二,满足条件的一组解的判决条件为:j>=v[i-1] && F[i][j] && F[i-1][j-v[i-1]]。
package com.yck.ds.dp;

import java.util.ArrayList;
import java.util.List;

public class Pack {
public int[] dp(int[] w, int s){
int M = w.length+1, N = s+1;
boolean stat[][] = new boolean[M][N];
stat[0][0]  = true;
for(int i=1;i<M;i++){
for(int j= 0;j<N;j++){
if(j<w[i-1]){//第i个物体不能装
stat[i][j] = stat[i-1][j];
}else{//第i个物体要转入
stat[i][j] = stat[i-1][j-w[i-1]] || stat[i-1][j];//前i-1可以选出 j重量或者j-w[i],则有解
}
}
}
int[] result = {-1};
//打印出可能的一组解
if(stat[M-1][N-1]){
List<Integer> ls = new ArrayList<Integer>();
int i=M-1,j=N-1;
while(i>0&&j>0){
if( j>=w[i-1] && stat[i-1][j-w[i-1]] && stat[i][j]){
ls.add(w[i-1]);
j = j-w[i-1];
}
i--;
}
            result = new int[ls.size()];
            for(int k=0;k<result.length;k++)
            {
                result[k]=ls.get(k);
            }
}
 
         return result;
}
public static void main(String[] args) {
Pack pack = new Pack();
int w[] = {1, 4, 4, 5, 7};
int arr[] = pack.dp(w, 10);
for (int i=0;i<arr.length;i++){
System.out.print(arr[i]);
}

}

}


发表于 2015-09-03 16:48:16 回复(0)
N件物品总重量相加,得到总的重量,然后利用组合,减去对应的物品的重量,得到能够装入物品的编号
发表于 2015-09-03 08:18:47 回复(0)
//动态规划解法:status[i][j]表示能否从1-i中选择若干其重量和为j
//status[itemNum][S]为true表示问题有解,再通过回溯输出结果
#include <iostream>

using namespace std;

const int MAX_ITEM_NUM = 10;
const int MAX_TOTAL_WEIGHT = 10000;
int weights[MAX_ITEM_NUM];
bool status[MAX_ITEM_NUM][MAX_TOTAL_WEIGHT];
int S;
int itemNum;

int main()
{
	cin >> S;
	cin >> itemNum;
	for(int i=1; i<=itemNum; ++i)
	{
		cin >> weights[i];
	}

	for(int i=0; i<=itemNum; ++i)
	{
		status[i][0] = true;
	}

	for(int i=1; i<=itemNum; ++i)
	{
		for(int j=0; j<=S; ++j)
		{
			if(weights[i] > j)
			{
				status[i][j] = status[i-1][j];
			}
			else
			{
				status[i][j] = (status[i-1][j] || status[i-1][j-weights[i]]);
			}
		}//for(j)
	}//for(i)

	if(status[itemNum][S])
	{
		int tmpS = S;
		for(int i=itemNum-1; i>=0; --i)//回溯一个输出结果
		{
			if(status[i][tmpS-weights[i+1]])// status[i][tmpS-weights[i+1]]为真说明可以从1-i中找若干使其等于tmpS-weights[i+1],所以我们就可以选第i+1项
			{
				cout << weights[i+1] << " ";
				tmpS -= weights[i+1];
			}
		}
		cout << endl;
	}
	else
	{
		cout << "no " << endl;
	}

	system("pause");
	return 0;
}

发表于 2015-09-02 09:01:52 回复(0)
<pre class="prettyprint lang-java"> <pre class="prettyprint lang-java"><span style="color:#cc7832;">public class </span>Bag { <span style="color:#cc7832;">public static void </span><span style="color:#ffc66d;">main</span>(String[] args) { <span style="color:#cc7832;">int</span>[] things = {<span style="color:#6897bb;">1</span><span style="color:#cc7832;">, </span><span style="color:#6897bb;">2</span><span style="color:#cc7832;">, </span><span style="color:#6897bb;">3</span><span style="color:#cc7832;">, </span><span style="color:#6897bb;">4</span><span style="color:#cc7832;">, </span><span style="color:#6897bb;">6</span><span style="color:#cc7832;">, </span><span style="color:#6897bb;">5</span><span style="color:#cc7832;">, </span><span style="color:#6897bb;">8</span><span style="color:#cc7832;">, </span><span style="color:#6897bb;">7</span>}<span style="color:#cc7832;">; </span><span style="color:#cc7832;"> int </span>S = <span style="color:#6897bb;">17</span><span style="color:#cc7832;">; </span><span style="color:#cc7832;"> </span><span>getBagRusult</span>(things<span style="color:#cc7832;">, </span>S)<span style="color:#cc7832;">; </span><span style="color:#cc7832;"> </span>} <span style="color:#cc7832;">public static void </span><span style="color:#ffc66d;">getBagRusult</span>(<span style="color:#cc7832;">int</span>[] things<span style="color:#cc7832;">, int </span>S) { <span style="color:#cc7832;">int </span>N = things.<span style="color:#9876aa;">length</span><span style="color:#cc7832;">; </span><span style="color:#cc7832;"> int </span>sum = <span style="color:#6897bb;">0</span><span style="color:#cc7832;">; </span><span style="color:#cc7832;"> for </span>(<span style="color:#cc7832;">int </span>i = <span style="color:#6897bb;">0</span><span style="color:#cc7832;">; </span>i &lt; N<span style="color:#cc7832;">; </span>i++) { <span style="color:#cc7832;">if </span>(sum &lt;= S &amp;&amp; (sum + things[i]) &gt; S) { things[i] = <span style="color:#6897bb;">0</span><span style="color:#cc7832;">; </span><span style="color:#cc7832;"> </span><span style="color:#cc7832;"> continue; </span><span style="color:#cc7832;"> </span>} <span style="color:#cc7832;">else if</span>(sum &lt; S){ sum += things[i]<span style="color:#cc7832;">; </span><span style="color:#cc7832;"> </span>} } <span style="color:#cc7832;">if </span>(sum == S) { System.<span style="color:#9876aa;">out</span>.println(<span style="color:#6a8759;">"has a solution,solution is"</span>)<span style="color:#cc7832;">; </span><span style="color:#cc7832;"> </span><span>printResult</span>(things)<span style="color:#cc7832;">; </span><span style="color:#cc7832;"> </span>} <span style="color:#cc7832;">else </span>{ System.<span style="color:#9876aa;">out</span>.println(<span style="color:#6a8759;">"do not hava a solution"</span>)<span style="color:#cc7832;">; </span><span style="color:#cc7832;"> </span>} } <span style="color:#cc7832;">public static void </span><span style="color:#ffc66d;">printResult</span>(<span style="color:#cc7832;">int</span>[] things) { <span style="color:#cc7832;">for </span>(<span style="color:#cc7832;">int </span>i = <span style="color:#6897bb;">0</span><span style="color:#cc7832;">; </span>i &lt; things.<span style="color:#9876aa;">length</span><span style="color:#cc7832;">; </span>i++) { <span style="color:#cc7832;">if </span>(things[i] != <span style="color:#6897bb;">0</span>) { System.<span style="color:#9876aa;">out</span>.print(things[i] + <span style="color:#6a8759;">","</span>)<span style="color:#cc7832;">; </span><span style="color:#cc7832;"> </span>} } } }</pre> </pre> <br />
发表于 2015-08-31 10:37:18 回复(0)
1
发表于 2015-08-11 17:32:04 回复(0)