0-1背包问题笔记

0-1背包问题

2 2 6 5 4

6 3 5 4 6

C[i][j]=max{C[i-1][j],C[i-1][j-wi]+vi} j>=wi这一步就是考虑将该物品可以装入的情况下,是否可以是一定质量下价值最大  就是判断在抉择某一物品时,重量从0到W的最佳抉择方案

或者

C[i][j]=C[i-1][j] j<wi因为达不到那个重量,所以不可能装入该物品,所以此物品没有被装入

以上这个公式非常重要,要是通过这个公式理解了挑选物品的规划过程,0-1背包问题就理解了。

当i从1开始到n-1的过程中,不断的探索C[i][j](0<=j<=W)的值,选出一个最优值。

当j从0到W的变化过程中,探索不同重量能获得的价值。

我觉得最妙的地方在于,它会从该物品放入或者没有放入两种情况中选择一种最优值放入。

    0  1  2  3  4  5  6  7  8  9  10
0  0  0  0  0  0  0  0  0  0  0  0
1  
2
3
4
5
代码如下:

#include <iostream>

using namespace std;

struct Weight_Value{
int weight;
int value;
};

int n;
int W;
int *Weight;
int *Value;
Weight_Value *p;
int point;

void function_0_1(){
      p=new Weight_Value[1000];
      Weight_Value *q=new Weight_Value[1000];
      Weight_Value *tempArr=new Weight_Value[1000];

      int p_next=1;
      int q_next=1;

      p[0].weight=0;
      p[0].value=0;
      for(int i=0;i<n;i++){
                  point=0;
            for(int j=0;j<=p_next-1;j++){
                  tempArr[j].weight=p[j].weight;
                  tempArr[j].value=p[j].value;
            }

            for(int j=0,k=0;j<=q_next-1;){//对q[i]进行处理
                  if(p[j].weight+Weight[i]>W){
                              q_next--;
                              continue;
                  }
                   q[j].weight=p[j].weight+Weight[i];
                   q[j].value=p[j].value+Value[i];
                   j++;
            }

            for(int j=0,k=0;j<=p_next-1||k<=q_next-1;){//求p[i]和q[i]的并集
                  if(j<=p_next-1&&tempArr[j].weight<=q[k].weight){
                        if(tempArr[j].weight==q[k].weight&&tempArr[j].value<q[k].value){
                              p[point].weight=q[k].weight;
                              p[point++].value=q[k++].value;
                               continue;
                        }
                        p[point].weight=tempArr[j].weight;
                        p[point++].value=tempArr[j++].value;
                  }
                  else if(k<=q_next-1&&q[k].value>tempArr[j-1].value){
                              while(j<=p_next-1&&q[k].value>tempArr[j].value)j++;

                        p[point].weight=q[k].weight;
                        p[point++].value=q[k++].value;
                  }
                  else if(k>q_next-1){
                                    if(tempArr[j].weight>=q[k-1].weight&&tempArr[j].value>q[k-1].value){
                                    p[point].weight=tempArr[j].weight;
                                    p[point++].value=tempArr[j++].value;
                                    }
                                    else j++;
                  }
                  else k++;
            }
            p_next=point;
            q_next=point;
      }
}

int main()
{
    //cout<<"请输入容量:"<<endl;
    cin>>W;
     //cout<<"请输入物品个数:"<<endl;
    cin>>n;
    Value=new int[n];
    Weight=new int[n];
    for(int i=0;i<n;i++){
      //cout<<"请输入第"<<i+1<<"物品的质量和重量:"<<endl;
      cin>>Weight[i]>>Value[i];
    }

    function_0_1();
    cout<<"以下是对p进行输出:"<<endl;
    cout<<"point="<<point<<endl;
    for(int i=0;i<point;i++)cout<<p[i].weight<<" "<<p[i].value<<endl;
    return 0;
}
测试如下数据通过:
1000 100
88 53
85 70
59 20
100 41
94 12
64 71
79 37
75 87
18 51
38 64
47 63
11 50
56 73
12 83
96 75
54 60
23 96
6 70
19 76
31 25
30 27
32 89
21 93
31 40
4 41
30 89
3 93
12 46
21 16
60 4
42 41
42 29
78 99
6 82
72 42
25 14
96 69
21 75
77 20
36 20
42 56
20 23
7 92
46 71
19 70
24 1
95 63
3 18
93 11
73 68
62 33
91 6
100 82
58 69
57 78
3 48
32 95
5 42
57 53
50 99
3 15
88 76
67 64
97 39
24 48
37 83
41 21
36 75
98 49
52 73
75 85
7 28
57 31
23 86
55 63
93 12
4 71
17 35
5 21
13 17
46 73
48 18
28 7
24 51
70 94
85 88
48 46
48 77
55 80
93 95
6 31
8 80
12 32
50 45
95 5
66 30
92 51
25 63
80 43
16 9

结果:2852


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我明白了。关于分支限界法的01背包问题,我可以给你一些思路和算法实现的笔记。 首先,01背包问题是指在有限的背包容量下,从给定的一组物品中选取一些物品放入背包中,使得背包中物品的总价值最大。而分支限界法则是一种解决优化问题的方法,它通过限制问题的搜索空间,逐步缩小问题的解空间,从而获得最优解。 对于01背包问题,我们可以采用以下步骤: 1. 构造一个搜索树,根节点代表空背包,每个节点代表向背包中添加一个物品或不添加物品的决策。 2. 对于每个节点,计算当前背包中物品的总价值以及还有多少容量可以使用。 3. 对于每个未被扩展的节点,计算它的上界价值(即背包在剩余容量中所能获得的最大价值),并按照上界价值从大到小排序。 4. 选择上界价值最大的节点进行扩展,即添加一个物品或不添加物品的两种决策分别扩展出两个子节点。 5. 不断重复步骤3和4,直到搜索树中的所有节点都被扩展完毕。 以下是一个简单的C语言实现,其中用一个结构体表示每个节点的状态,通过一个优先队列来实现按照上界价值排序的功能: ```c #include <stdio.h> #include <stdlib.h> #define MAX_N 1000 int n, c; int w[MAX_N], v[MAX_N]; int max_v; typedef struct Node { int level; int value; int weight; int bound; } Node; typedef struct PriorityQueue { Node* arr[MAX_N]; int size; } PriorityQueue; PriorityQueue* createPriorityQueue() { PriorityQueue* q = (PriorityQueue*)malloc(sizeof(PriorityQueue)); q->size = 0; return q; } void push(PriorityQueue* q, Node* node) { q->arr[q->size++] = node; int i = q->size - 1; while (i > 0 && q->arr[i]->bound > q->arr[(i - 1) / 2]->bound) { Node* temp = q->arr[i]; q->arr[i] = q->arr[(i - 1) / 2]; q->arr[(i - 1) / 2] = temp; i = (i - 1) / 2; } } Node* pop(PriorityQueue* q) { Node* node = q->arr[0]; q->arr[0] = q->arr[--q->size]; int i = 0; while (i * 2 + 1 < q->size) { int j = i * 2 + 1; if (j + 1 < q->size && q->arr[j + 1]->bound > q->arr[j]->bound) { j++; } if (q->arr[i]->bound < q->arr[j]->bound) { Node* temp = q->arr[i]; q->arr[i] = q->arr[j]; q->arr[j] = temp; i = j; } else { break; } } return node; } void solve() { PriorityQueue* q = createPriorityQueue(); Node* root = (Node*)malloc(sizeof(Node)); root->level = 0; root->value = 0; root->weight = 0; root->bound = max_v; push(q, root); while (q->size > 0) { Node* node = pop(q); if (node->bound <= max_v || node->level == n) { continue; } Node* left = (Node*)malloc(sizeof(Node)); left->level = node->level + 1; left->value = node->value + v[left->level]; left->weight = node->weight + w[left->level]; if (left->weight <= c) { left->bound = left->value + (max_v - left->value) * 1.0 / w[left->level]; if (left->value > max_v) { max_v = left->value; } push(q, left); } Node* right = (Node*)malloc(sizeof(Node)); right->level = node->level + 1; right->value = node->value; right->weight = node->weight; right->bound = right->value + (max_v - right->value) * 1.0 / w[right->level]; push(q, right); } } int main() { scanf("%d%d", &n, &c); for (int i = 1; i <= n; i++) { scanf("%d%d", &w[i], &v[i]); max_v += v[i]; } solve(); printf("%d", max_v); return 0; } ``` 希望这些笔记能够对你有所帮助,如果有任何问题,欢迎随时问我。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值