01背包问题
参考了http://www.cnblogs.com/qinyg/archive/2012/04/26/2471829.html
关键的状态转移方程如下
令V(i,j)表示在前i(1<=i<=n)个物品中能够装入容量为就j(1<=j<=C)的背包中的物品的最大价值,则可以得到如下的动态规划函数:
(1) V(i,0)=V(0,j)=0
(2) V(i,j)=V(i-1,j) j<wi
V(i,j)=max{V(i-1,j) ,V(i-1,j-wi)+vi) } j>wi
(1)式表明:如果第i个物品的重量大于背包的容量,则装人前i个物品得到的最大价值和装入前i-1个物品得到的最大价是相同的,即物品i不能装入背包;第(2)个式子表明:如果第i个物品的重量小于背包的容量,则会有一下两种情况:(a)如果把第i个物品装入背包,则背包物品的价值等于第i-1个物品装入容量位j-wi 的背包中的价值加上第i个物品的价值vi; (b)如果第i个物品没有装入背包,则背包中物品价值就等于把前i-1个物品装入容量为j的背包中所取得的价值。显然,取二者中价值最大的作为把前i个物品装入容量为j的背包中的最优解。
用poj3624练手
第一次开二维dp数组,直接超内存
第二次用两个一维数组交替,内存是没超,但是耗时400多ms,而且代码比较丑陋
1 #include <iostream> 2 #include <string> 3 #include <sstream> 4 #include <vector> 5 6 using namespace std; 7 8 9 int main() 10 { 11 int n, m; 12 cin >> n >> m; 13 int *w = (int*)malloc(sizeof(int)*(n+1)); 14 int *d = (int*)malloc(sizeof(int)*(n + 1)); 15 16 int *dp = (int *)(malloc(sizeof(int)*(m+1))); 17 int *dp_t = (int *)(malloc(sizeof(int)*(m + 1))); 18 19 memset(dp, 0, sizeof(int)*(m + 1)); 20 21 for (int i = 1; i <= n; i++) 22 { 23 cin >> w[i] >> d[i]; 24 } 25 26 for (int i = 1; i <= n; i++) 27 { 28 memset(dp_t, 0, sizeof(int)*(m + 1)); 29 30 for (int j = 1; j <= m; j++) 31 { 32 int x = dp[j]; 33 int y = 0; 34 if(j >= w[i]) 35 y = dp[j - w[i]] + d[i]; 36 dp_t[j] = x < y ? y : x; 37 38 } 39 40 memcpy(dp, dp_t, sizeof(int)*(m + 1)); 41 } 42 43 cout << dp[m] << endl; 44 45 //system("pause"); 46 }
看了一下别人的代码,才发现有更优雅的处理方法,修改后代码如下,耗时也缩短为不到300ms
1 #include <iostream> 2 #include <string> 3 #include <sstream> 4 #include <vector> 5 6 using namespace std; 7 8 int dp[12900]; 9 int w[3410], d[3410]; 10 11 int main() 12 { 13 int n, m; 14 cin >> n >> m; 15 16 memset(dp, 0, sizeof(dp)); 17 18 for (int i = 1; i <= n; i++) 19 { 20 cin >> w[i] >> d[i]; 21 } 22 23 for (int i = 1; i <= n; i++) 24 { 25 26 for (int j = m; j > 0; j--) 27 { 28 int x = dp[j]; 29 int y = 0; 30 if(j >= w[i]) 31 y = dp[j - w[i]] + d[i]; 32 dp[j] = x < y ? y : x; 33 } 34 } 35 36 cout << dp[m] << endl; 37 38 //system("pause"); 39 }