zoukankan      html  css  js  c++  java
  • 0-1背包

    0-1背包

            给定n种物品和一背包,物品i的重量是wi,其价值是pi,背包的容量是M,问如何选择装入背包中的物品总价值最大?

             背包的背负有上限,因此在这个上限内尽可能多的装东西,并且价值越多越好

    •    0-1背包问题的解决办法
           穷举算法
          动态规划算法
          贪心算法(未必获得最优解)
          回溯算法
    •动态规划算法

              建立递归关系

          c[i][m]=max{c[i-1][m], c[i-1][m-w[i]]+p[i]}

           计算最优值

     

           0-1背包的动态规划算法(周志光老师的课件代码):

     1 # include<stdio.h>
     2 int c[20][20];    //c[i][j],i件物品j的容量能放得最大价值
     3 int w[20];    //体积(重量)
     4 int p[20];    //价值
     5 int x[20];  //第i见物品是否装入背包
     6 //n件物品,背包容量m
     7 int knapsack(int m,int n)    //0-1背包动态规划求解
     8 {
     9     int i,j,k;
    10     for(i=0; i<n+1; i++)
    11         for(j=0; j<m+1; j++)
    12             c[i][j]=0;
    13     for(i=1; i<n+1; i++)
    14         for(j=1; j<m+1; j++)
    15         {
    16             if(w[i]<=j)
    17             {
    18                 if(p[i]+c[i-1][j-w[i]]>c[i-1][j])
    19                     c[i][j]=p[i]+c[i-1][j-w[i]];
    20                 else
    21                     c[i][j] = c[i-1][j];
    22             }
    23             else
    24                 c[i][j] = c[i-1][j];
    25         }
    26     return c[n][m];
    27 }
    28 void traceBack(int n, int m)  //构造最优解
    29 {
    30     int i;
    31     for (i = n; i > 0; i--)
    32     {
    33         if (c[i][m] == c[i-1][m]) x[i] = 0;
    34         else
    35         {
    36             x[i] = 1;
    37             m -= w[i];
    38         }
    39     }
    40     printf("n个物品装入背包情况是:");
    41     for (i = 1; i < n+1; i++) printf(" %d",x[i]);
    42     puts("");
    43 }
    44 int main()
    45 {
    46     int i,n,m,j;
    47     while(scanf("%d%d",&n,&m)!=EOF)
    48     {
    49         for(i=1; i<=n; i++)
    50             scanf("%d%d",&w[i],&p[i]);
    51         printf("背包能获得的最大价值 = %d
    ",knapsack(m,n));
    52         traceBack(n,m);
    53     }
    54     return 0;
    55 }

    •回溯算法

        解空间定义
          例如:0-1背包问题中,当n=3时,其解空间为:
             (0,0,0),(0,0,1),(0,1,0),(0,1,1),
            (1,0,0),(1,0,1),(1,1,0),(1,1,1)
        解空间树
     
        深度优先遍历
           假设给定图G的初态是所有顶点均未曾访问过。在G中任选一顶点v为初始出发点(源点),则深度优先遍历可定义如下:首先访问出发点v,并将其标记为已访问过;然后依次从v出发搜索v的每个邻接点w。若w未曾访问过,则以w为新的出发点继续进行深度优先遍历,直至图中所有和源点v有路径相通的顶点(亦称为从源点可达的顶点)均已被访问为止。若此时图中仍有未访问的顶点,则另选一个尚未访问的顶点作为新的源点重复上述过程,直至图中所有顶点均已被访问为止。
        剪枝函数
            算法搜索至解空间树的任一结点时,总先判断该结点是否肯定不包含问题的解。如果肯定不包含,则跳过对该结点为根的子树的系统搜索,逐层向其祖先结点回溯。
            分类:条件约束、限界函数
     
        0-1背包的回溯算法(周志光老师的课件代码):
     1 # include<stdio.h>
     2 int c;      //背包能承受的最大重量
     3 int n;      //背包能装的最多的物品数
     4 int cw;     //背包现在的载重
     5 int cp;     //背包现在的价值
     6 int bestp;  //背包的最大价值
     7 int w[50],p[50];//物品的重量和价值
     8 int x[50],bestx[50];
     9 //最优状态下,如果第i个物品装入背包,那么bestx[i]=1;否则为0
    10 int Bound(int i) //计算上界,限界函数
    11 {
    12     int cleft=c-cw;//剩余容量
    13     int b=cp;
    14     //以物品单位重量价值递减序装入物品
    15     while(i<=n&&w[i]<=cleft)
    16     {
    17         cleft-=w[i];
    18         b+=p[i];
    19         i++;
    20     }
    21     if(i<=n) //装满背包
    22         b+=p[i]/w[i]*cleft;
    23     return b;
    24 }
    25 void backTrack(int i)
    26 {
    27     if(i>n)
    28     {
    29         if(bestp<cp)
    30         {
    31             for(int j=1; j<=n; j++)
    32                 bestx[j]=x[j];
    33             bestp=cp;
    34         }
    35         return;
    36     }
    37     if(cw+w[i]<=c) //搜索左子树
    38     {
    39         x[i]=1;
    40         cw+=w[i];
    41         cp+=p[i];
    42         backTrack (i+1);
    43         cw-=w[i];
    44         cp-=p[i];
    45     }
    46     if(Bound(i+1)>bestp) //搜索右子树
    47     {
    48         x[i]=0;
    49         backTrack (i+1);
    50     }
    51 }
    52 int main()
    53 {
    54     int i;
    55     while(scanf("%d%d",&n,&c)!=EOF)
    56     {
    57         for(i=1; i<=n; i++)
    58         {
    59             scanf("%d%d",&w[i],&p[i]);
    60         }
    61         cw=0;
    62         cp=0;
    63         bestp=0;
    64         backTrack(1);
    65         printf("背包能获得的最大价值 = %d
    ",bestp);
    66         printf("n个物品装入背包情况是:");
    67         for(i=1;i<=n;i++)
    68         printf(" %d",bestx[i]);
    69         puts("");
    70     }
    71     return 0;
    72 }
  • 相关阅读:
    linux下后台执行shell脚本nohup
    notepad++常用命令
    dmidecode查看硬件信息
    CSV文件自动化(自定义参数)
    服务器数据恢复案例分享-硬盘掉线恢复
    DELL EqualLogic PS6100存储硬盘坏道数据恢复
    成功恢复某服务器丢失数据过程
    分析Linux raid6同步成raid5导致数据丢失的情况
    服务器RAID硬盘离线和数据库损坏数据恢复方法
    chkdsk 后数据丢失的恢复方法
  • 原文地址:https://www.cnblogs.com/acm-bingzi/p/3149727.html
Copyright © 2011-2022 走看看