背包问题(C语言)

01背包

问题描述
有n件物品(是件不是种!),每件物品有自己的重量w[n]和价值v[n];现有一个容量为bag的背包,要在背包容量满足的条件下将物品们装入背包,使总价值最大,试问应该怎样放入?最大值为多少?

基本思路
该问题中每个物体仅有放入或不放入两种情况,故称为01背包问题。
现有二元函数maxvalue(i,wight) 表示在考虑前i件物体的情况下,容量为wight的背包所能达到的最大价值。
考虑是否放入第i个物体:
若不放入,则有maxvalue(i,wight)=maxvalue(i-1,wight) ;
若放入,则有maxvalue(i,wight)= maxvalue(i-1,wight-w[i])+ v[i] 。
故该函数满足以下递归式:

maxvalue(i,wight)=max { maxvalue(i-1, wight) , maxvalue(i-1,wight-w[i])+v[i] }

建立二维数组maxvalue[n+1][wight+1],由动态规划打表即可求出每个状态下的maxvalue值,其中maxvalue[n+1][wight+1]的值即为所求。再通过对该值进行递归回溯,即可找到满足该值的物品组成。

下面是代码

#include 

int max(int a, int b)
{
    return a > b ? a : b;
}

int main() 
{
    int n, bag;//n为物体个数,bag为背包容量
    printf("\n请输入物体个数和背包容量:\n");
    scanf("%d %d",&n,&bag);
    int w[100];//每个物体重量
	int v[100];//每个物体价值
    printf("请依次输入每个物体的重量和价值:\n");
    for(int i = 1; i <= n; i++)
    {
        scanf("%d %d", &w[i], &v[i]);
    }
	int maxvalue[100][100] = {0};//动态规划表
    //制表
	for (int i = 1; i <= n; i++) 
    {
		for (int wight = 1; wight <= bag; wight++)
        {
			if (wight < w[i])
				maxvalue[i][wight] = maxvalue[i-1][wight];
			else
				maxvalue[i][wight] = max(maxvalue[i-1][wight], maxvalue[i-1][wight-w[i]] + v[i]);
		}
	}
    //打表
    printf("w i g h t: ");
    for(int wight=1; wight <= bag; wight++) printf("%-3d", wight);
    printf("\n");
    for(int i = 1; i <= n; i++)
    {
        printf("w%d,v%-3di=%d ", w[i],v[i], i);
        for(int wight = 1; wight <= bag; wight++)
        {
            printf("%-3d", maxvalue[i][wight]);
        }
        printf("\n");
    }
    printf("\n");
    //输出最大值
    printf("MAX=%d\n", maxvalue[n][bag]);
    //最大值回溯
    int judge[100] = {0};
    int x = n, y = bag;
    while(x != 0 && y != 0)
    {
        if(maxvalue[x][y] != maxvalue[x-1][y])
        {
            judge[x]++;
            y-=w[x];
            x--;
        }
        else x--;
    }
    //输出满足条件的物体
    for(int i = 1; i <= n; i++)
    {
        if(judge[i]) printf("NO.%d wight%d value%d\n", i, w[i], v[i]);
    }
}

 
 

多重背包

问题描述:
在01背包的基础上,现在每件物体的数量不再为1,而是各自给定,依然求满足题意的最大总价值。

基本思路:
很容易想到,我们可以模仿01背包的做法,将n件某种物体分为n个1件同种物体,再01背包一下。这样就会增加n件物体。为了减少增加的物体个数,我们可以利用二进制优化。
有引理:

n以内的正整数,都可以用1, 2, 4,…, 2(k-1), n-2k+1中任意几个数之和表示

于是,对于n件某种物体,我们便可以增加k个物体,每个物体的重量和价值分别为原物体的1, 2, 4,…, 2(k-1), n-2k+1倍,这样便可以模拟该种物体放0~n个的所有情况。

#include 
#include 

int max(int a, int b)
{
    return a > b ? a : b;
}

int main() 
{
    int n, bag;
    scanf("%d %d",&n,&bag);  //物体种数,背包容量
    int w[110], v[110], num[110];
    //转化为多重背包
    int w1[5000];
	int v1[5000];
    for(int i = 1; i <= n; i++)
    {
        scanf("%d %d %d", &w[i], &v[i], &num[i]);  //重量,价值,数量
    }

    int dp[10000];
    int index = 0;
    for(int i = 1;i <= n;i++)
    {
        int t = num[i], k = 1;
        while(t - k > 0)
        {
            t -= k;
            w1[++index] = k * w[i];
            v1[index] = k * v[i];
        }
        w1[++index] = t * w[i];
        v1[index] = t * v[i];
    }
    memset(dp,0,sizeof(dp));
    for(int i = 1;i <= index;i++)
        for(int j = bag;j >= w1[i];j--)
            dp[j] = max(dp[j],dp[j - w1[i]] + v1[i]);
    printf("%d\n",dp[bag]);
}

你可能感兴趣的:(背包问题(C语言))