View Code
1 // 背包问题.cpp : 定义控制台应用程序的入口点。 2 // 3 //来自背包九讲 4 5 6 /****************************/ 7 /* 8 设计者:cslave 9 代码说明: 背包问题 10 */ 11 #include "stdafx.h" 12 #include <iostream> 13 using namespace std; 14 #define NumItem 10 15 #define Max 100 16 typedef int CapType; 17 typedef int ValueType; 18 CapType Capacity=Max; 19 20 21 ValueType f[NumItem][Capacity]; 22 CapType Cost[NumItem]; 23 ValueType Weight[NumItem]; 24 int Amount[NumItem]; 25 26 27 /*****************01背包问题**************************/ 28 /* 29 题目:有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。 30 31 状态转移方程: 32 33 用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其状态转移方程便是: 34 35 f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]} 36 37 时间和空间复杂度均为O(VN) 38 39 伪代码: 40 procedure ZeroOnePack(cost,weight) 41 for v=V..cost 42 f[v]=max{f[v],f[v-cost]+weight} 43 44 45 procedure Pack(cost[],weight[]) 46 for i=1..N 47 ZeroOnePack(c[i],w[i]); 48 49 */ 50 /******************分割线***************************/ 51 void ZeroOnePack(CapType Cost,ValueType Weight) 52 { 53 for(CapType v=Capcity;v>=Cost;v--) 54 f[v]=f[v]>f[v-Cost]+Weight?f[v]:f[v-Cost]+Weight; 55 } 56 57 void Pack() 58 { 59 for(int i=0;i<NumItem;i++) 60 ZeroOnePack(Cost[i],Weight[i]); 61 } 62 63 64 65 66 67 68 69 /***********************完全背包问题***************************/ 70 /* 71 题目:有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。 72 求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。 73 74 75 76 状态转移方程: 77 用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其状态转移方程便是: 78 79 f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k*c[i]<=v} 80 81 时间复杂度O(VN) 82 83 伪代码: 84 for i=1..N 85 for v=0..V 86 f[v]=max{f[v],f[v-cost]+weight} 87 88 89 */ 90 /************************分割线*********************************/ 91 void CompletePack(CapType Cost,ValueType Weight) 92 { 93 for(CapType v=Cost;v<=Capcity;v++) 94 f[v]=f[v]>f[v-Cost]+Weight?f[v]:f[v-Cost]+Weight; 95 } 96 97 void Pack() 98 { 99 for(int i=0;i<NumItem;i++) 100 CompletePack(Cost[i],Weight[i]); 101 } 102 103 104 105 106 107 108 109 110 111 112 /*************************多重背包********************************/ 113 /* 114 题目:有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。 115 求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。 116 117 状态转移方程: 118 这题目和完全背包问题很类似。基本的方程只需将完全背包问题的方程略微一改即可,因为对于第i种物品有n[i]+1种策略: 119 取0件,取1件……取n[i]件。令f[i][v]表示前i种物品恰放入一个容量为v的背包的最大权值,则有状态转移方程: 120 121 f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k<=n[i]} 122 123 复杂度是O(V*Σn[i])。 124 125 126 127 伪代码: 128 procedure MultiplePack(cost,weight,amount) 129 if cost*amount>=V 130 CompletePack(cost,weight) 131 return 132 integer k=1 133 while k<amount 134 ZeroOnePack(k*cost,k*weight) 135 amount=amount-k 136 k=k*2 137 ZeroOnePack(amount*cost,amount*weight) 138 139 procedure Pack(cost[],weight[]) 140 for i=1..N 141 MultiplePack(c[i],w[i]); 142 143 */ 144 145 /*************************分割线***********************************/ 146 void MultiplePack(CapType Cost,ValueType Weight,int Amount) 147 { 148 if (Cost*Amount>=Capacity) 149 { 150 CompletePack(Cost,Weight); 151 return; 152 } 153 int k=1; 154 while(k<Amount) 155 { 156 ZeroOnePack(k*Cost,k*Weight); 157 Amount=Amount-k; 158 k=k*2; 159 } 160 ZeroOnePack(Amount*Cost,Amount*Weight); 161 } 162 163 void Pack(CapType Cost[],ValueType weight[]) 164 { 165 for(int i=0;i<NumItem;i++) 166 MultiplePack(cost[i],Weight[i],Amount[i]); 167 }