【DP问题集】动态规划试题
1.背包问题
给定n种物品和一背包。物品i的重量是wi,其价值为pi,背包的容量为C。问应如何选择装入背包的物品,使得装入背包中物品的总价值最大?
分析:
①每个物品只有两种选择,要么就是塞到包里面,要么就是不要了;
②当背包剩余容量为j时,如果第i件物品重量wi>j时,必定是要不了的,如果wi<j时,可以选择要或者不要,因为要了之后背包空间减少,会影响后面的选择;
③假设剩余容量j的背包从i到n这n-i+1种物品中能选出的最大总价值记为m[i,j],那么对于原问题:容量为C的背包,从1到n中物品中能选出的最大总价值则可以记为m[1,C];
④寻找递推式——动态规划,其实就是用递推来代替递归,利用多个相同或者不同的子问题的输出得出一个包含这些子问题的输出,是典型的牺牲空间换取速度的做法。
那么m[i,j]可以分为两种情况
当已知m[i+1,j]时,
m[i,j] = m[i+1, j] , wi>j
m[i,j] = max(m[i+1, j], m[i+1, j-wi]+pi) , wi<j (此处的m[i+1, j-wi]是因为决定选择第i个物品时,剩余空间减少为j-wi)
举个例子:
假设现有5种物品,且它们的重量和价值分别如下所示:
n | 1 | 2 | 3 | 4 | 5 |
wi | 1 | 2 | 3 | 4 | 5 |
pi | 2 | 3 | 6 | 4 | 7 |
j\i | 1 | 2 | 3 | 4 | 5 |
1 | 2 | 0 | 0 | 0 | 0 |
2 | 3 | 3 | 0 | 0 | 0 |
3 | 6 | 6 | 6 | 0 | 0 |
4 | 8 | 6 | 6 | 4 | 0 |
5 | 9 | 9 | 7 | 7 | 7 |
6 | 11 | 9 | 7 | 7 | 7 |
7 | ?=11 | 10 | 10 | 7 | 7 |
2.最长递增序列
给定一个序列,求至少删除几个数,使得序列呈递增序列,返回最长递增序列长度。(递增序列要求ai≤ai+1)
<分析明天给出,敬请期待>
#include <stdio.h> #include <stdlib.h> int input_array(int **a){ int n, k; scanf("%d", &n); *a = (int*)malloc(sizeof(int)*n); for(k=0; k<n; k++){ scanf("%d", *a+k); } return n; } int maxlen(int *a, int n){ int k, mk; int *m; int mlen; if(a==NULL) return 0; m = (int*)malloc(sizeof(m)*n); if(m==NULL) return 0; //初始化dptemp *m = *a; mlen = 1; for(k=1; k<n; k++){ for(mk=mlen-1; mk>=0; mk--){ if(*(a+k)>=*(m+mk)){ if(mk==mlen-1){ *(m+mlen) = *(a+k); mlen++; } else{ if(*(a+k)<=*(m+mk+1)) *(m+mk+1) = *(a+k); } break; } } if(mk==-1){ if(*(a+k)<*m) *m = *(a+k); } } free(m); return mlen; } int main(void){ int *a, n; n = input_array(&a); printf("maxlen = %d\n", maxlen(a, n)); system("pause"); return 0; }