01背包、完全背包、最长上升子序列

来源:互联网 发布:chromebook ubuntu 编辑:程序博客网 时间:2024/06/05 03:13

1、01背包

题目

N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。

例如:http://codevs.cn/problem/1014/


#include<iostream>#include<algorithm>using namespace std;//dp初值为0int dp[100000] = { 0 };int main() {//freopen("data.txt", "r", stdin);//M为背包最大体积,N表示物品数量int M, N;cin >> M >> N;//w表示第i件物品的重量,c表示第i件物品的价值int c, w;//i:1<=i<=N//j:w<=j<=M,M-w递减for (int i = 1; i <= N; i++) {cin >> c >> w;for (int j = M; j >= w; j--) {dp[j] = max(dp[j], dp[j - w] + c);}}cout << dp[M] << endl;return 0;}

有的题目要求恰好装满背包时的最优解,有的题目则并没有要求必须把背包装满。一种区别这两种问法的实现方法是在初始化的时候有所不同。

如果是第一种问法,要求恰好装满背包,那么在初始化时除了f[0]0其它f[1..V]均设为-∞,这样就可以保证最终得到的f[N]是一种恰好装满背包的最优解。

如果并没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该将f[0..V]全部设为0

为什么呢?可以这样理解:初始化的f数组事实上就是在没有任何物品可以放入背包时的合法状态。如果要求背包恰好装满,那么此时只有容量为0的背包可能被价值为0nothing“恰好装满其它容量的背包均没有合法的解,属于未定义的状态,它们的值就都应该是-∞。如果背包并非必须被装满,那么任何容量的背包都有一个合法解什么都不装,这个解的价值为0,所以初始时状态的值也就全部为0了。

2、完全背包

题目

N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

例如:http://codevs.cn/problem/2029/

#include<iostream>#include<algorithm>using namespace std;//dp初值为0int dp[100000] = { 0 };int main() {//freopen("data.txt", "r", stdin);//M为背包最大体积,N表示物品数量int M, N;cin >> M >> N;//w表示第i件物品的重量,c表示第i件物品的价值int c, w;//i:1<=i<=N//j:w<=j<=M,w-for (int i = 1; i <= N; i++) {cin >> c >> w;for (int j = w; j <= M; j++) {dp[j] = max(dp[j], dp[j - w] + c);}}cout << dp[M] << endl;return 0;}

3、最长上升子序列

某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。

  

输入描述 Input Description

输入导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数)

  

输出描述 Output Description

输出这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

样例输入 Sample Input

389 207 155 300 299 170 158 65 

样例输出 Sample Output

6

2

分析这个题目可知,一个拦截系统能拦截导弹的最大数目就是输入序列中最长非递增子序列的长度,而拦截系统的数目就是输入序列中最长递增子序列的长度

#include<iostream> #include<algorithm> #include<stdio.h> using namespace std;int a[10010];int up[10010];int down[10010];int upans,downans=0;int main(){    int n=0;    //读文件一直到文件结尾    while(cin>>a[n]){            up[n]=1;            down[n]=1;            n++;    }    //i:1~n    //j:0~i    for(int i=1;i<n;i++){        for(int j=0;j<i;j++){                //非递增                if(a[i]<=a[j])down[i]=max(down[i],down[j]+1);                //递增                else up[i]=max(up[i],up[j]+1);        }        //更新        downans=max(downans,down[i]);        upans=max(upans,up[i]);    }    cout<<downans<<endl<<upans<<endl;    return 0; }


原创粉丝点击