【算法实验二】--【回溯法】--0 1背包问题

1004.0-1背包问题

时限:1000ms 内存限制:10000K  总时限:3000ms

描述

需对容量为c 的背包进行装载。从n 个物品中选取装入背包的物品,每件物品i 的重量为wi ,价值为pi 。对于可行的背包装载,背包中物品的总重量不能超过背包的容量,最佳装载是指所装入的物品价值最高。

 

输入

多个测例,每个测例的输入占三行。第一行两个整数:n(n<=10)和c,第二行n个整数分别是w1到wn,第三行n个整数分别是p1到pn。
n 和 c 都等于零标志输入结束。

 

输出

每个测例的输出占一行,输出一个整数,即最佳装载的总价值。

 

输入样例

1 2
1
1
2 3
2 2
3 4
0 0

 

输出样例

1
4

解析:01背包问题有很多种解法,这里介绍两种。

第一种:回溯法。回溯法使用深度优先的搜索方式,搜索了01背包问题的解空间树的每一个节点,最后得出最优解。

#include<stdio.h>
#include<string.h>
int n,c;
int bestv=0,cw,cv;
int w[11],v[11];
void backpack(int cw,int cv,int i)//分别表示当前质量,当前价值,第i件东西
{
    if(i>n)//这里是容易犯错的地方,如果你是从0开始存的,那么这里的判断条件应该是i>=n或i>n-1
    {
        if(bestv<cv)
            bestv=cv;
    }
    else
    {
        if(w[i]+cw<=c)
            backpack(cw+w[i],cv+v[i],i+1);//如果能装下,就装,如果装不下,就直接不装,如果能装下,也可以不装
        backpack(cw,cv,i+1);
    }
}
int main()
{
    while(scanf(“%d%d”,&n,&c)&&(n||c))
    {
        memset(w,0,sizeof(w));
        memset(v,0,sizeof(v));
        bestv=0;cv=0;cw=0;//每次重新开始一组数时,数组和这些值都要重置为0
        for(int i=1;i<=n;i++)
            scanf(“%d”,&w[i]);
        for(int i=1;i<=n;i++)
            scanf(“%d”,&v[i]);
        backpack(0,0,1);
        printf(“%d\n”,bestv);
    }
    return 0;
}
第二种:动态规划法,动态规划法采用从底向上的方法,当前的每一步都会被记录下来,因为每一步都会对以后的结果产生影响,所以能用动态规划法做的题一般都能画出来一各表,储存了每一步的结果等待后面调用。例如这个0 1背包问题,就是画一个n*c的表格,具体实现如下:

#include<stdio.h>
#include<string.h>
int n,c;
int w[11],v[11];
int m[11][101];
int max(int a,int b)
{
    if(a>b)
        return a;
    else
        return b;
}
void package()
{
    for(int i=0;i<=n;i++)
        for(int j=0;j<=c;j++)
            m[i][j]=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=c;j++)
        {
            if(j>=w[i])
                m[i][j]=max(m[i-1][j-w[i]]+v[i],m[i-1][j]);//如果能装下,就选择装或者不装,看谁产生的最终价值大,最终价值一直要到最                                                                            //后一步才能确定下来
            else
                m[i][j]=m[i-1][j];
        }
    }
    printf(“%d\n”,m[n][c]);
}
int main()
{
    while(scanf(“%d%d”,&n,&c)&&(n||c))
    {
        memset(w,0,sizeof(w));
        memset(v,0,sizeof(v));
        memset(m,0,sizeof(m));
        for(int i=1;i<=n;i++)
            scanf(“%d”,&w[i]);
        for(int i=1;i<=n;i++)
            scanf(“%d”,&v[i]);
        package();
    }
    return 0;
}

注:动态规划可以解决01背包问题是因为其具有最优子结构性质,即最终的最优解所包含的子问题的解也是最优的,比如在这个所得的表格中,m[n][c]是容量为c时的最优解,m[n][c-1]是容量为c-1时的最优解,以此类推。最优子结构性质是一个问题可以用动态规划法所解决的必要条件,最优子结构性质导致问题所有子问题的解可以存储在一个表格里,以备后续调用,这也引出了动态规划法另一个基本性质,即子问题重叠性质,这也是动态规划从根本上高于回溯法的重要原因。
 

    原文作者:回溯法
    原文地址: https://blog.csdn.net/zhuge2017302307/article/details/84110993
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞