DP&&计数排序&&背包

**经典问题:树塔问题
结论:
自顶向下的分析,
自底向上的计算。

经典问题:最长有序子序列
N*N;
特点:最优子结构,无后效应,节约时间。
基本思想:
如果各个子问题不是独立的(即:重复的)。不同的子问题的个数是多项式量级(即:有限是),如果我们能够保存已经解决的子问题的答案(一般用数组),而在再需要的时候找出已求得的答案,这样就可以避免大量的重复计算。

//计数排序的C++实现方法
#include <iostream>
using namespace std;
const int MAXN = 100000;
const int k = 1000; // range(范围)
int a[MAXN], c[MAXN], ranked[MAXN];
 
int main() {
    int n;
    cin >> n;
    for (int i = 0; i < n; ++i) {
        cin >> a[i]; 
        ++c[a[i]];
    }
    for (int i = 1; i < k; ++i)
        c[i] += c[i-1];
    for (int i = n-1; i >= 0; --i)
        ranked[--c[a[i]]] = a[i];//如果是i表达的是原数标号,a[i]就是排序后的正确序列
    for (int i = 0; i < n; ++i)
        cout << ranked[i] << endl;
    return 0;
}
背包基本模型:
给你一个容量为V的背包和若干种物品,在一定的限制条件下(每种物品都占有一定的容量),问最多能放进多少价值的物品?
1、最典型、最基本的DP问题;
2、理解并熟练掌握背包问题意义重大;
3、DP问题中“状态”概念的理解;
4、背包的每个容量就是“状态”(思考一下被子倒水问题的状态转移);**

背包的分类:
1、01背包;
2、完全背包‘
3、多重背包;
4、二维费用背包;
5、混合三种背包;
6、分组背包;
7、有依赖的背包;

一、01背包
1、有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解写物品装入背包可使价值总和最大。
2、问题特点:每种物品仅有一件,可以选择放或者不放;
3、思考:在每个物品都有可能被选中的前提下,如何构造“子问题”?
4、无序变有序的方法:依次考虑前1、前2、前3…前i个物品;
5、状态定义:f[i][v]表示前i件物品放入一个容量为V 的背包可以获得的最大价值。

f[i-1][v],f[i-1][v-c[i]]+w[i],两种情况进行比较;
* 、问题分解:当前最优解,要么包含第i种物品,要么不包含第i种物品
* 、DP[i][j]表示前i个物品,背包容量为j的最优值。
* 、状态转移方程:DP[i][j] = max(DP[i-1][j]),DP[i-1][j-v[i]]+w[i]);
* /时间复杂度NV,空间复杂度N*V
*/空间复杂度优化:只用一维数组DP[j]来实现;

01背包问题伪代码;
for i = 1 to n //所有物品
for j = V to v[i] //思考:为何没必要循环到0?为了不出现负数,而且是以前的结果,没有意义;
dp[j] = max (dp[j],dp[j-v[i]]+w[i]);
空间成功优化到一维;

#include<bits/stdc++.h>
using namespace std;
int dp[1001],w[1000],c[1000];
int main(){
     int num,n,V,i,j;
     scanf("%d%d",&n.&V);
     while(num--){
     scanf("%d%d",&n,&V);
     for(i=0;i<n;i++) scanf("%d",&w[i]);
     for(i=0;i<n;i++) scanf("%d",&c[i]);
     memset(dp,o,sizeof(dp));
     for(i=0;i<n;i++)
        for(j=V;j>=c[i];j--)
           dp[j]=max(dp[j],dp[j-c[i]]+w[i]);
      printf("%d\n",dp[V]);
     }
     return 0;
}
/*
未优化的二维DP;
   dp[i][v]
   for(i=0;i<n;i++){
      dp=max(dp[i-1][v],dp[i-1][v-c[i]]+w[i]);
}
*/

二、完全背包
完全背包特点:一种物品可以取无数个
可否转化成01背包问题?可以暴力转化成01,但是会爆栈
朴素的转化方式是?
回忆01背包为何要对容量按照逆顺序循环?从前往后做
和01背包类似,不过就是正着写!
深度思考:这类能不能达到的问题应该怎么实现?
剩余空间无解就是没有解每次赋值需要判断

多重背包
转化成新物品,转化成01背包可以做的
比如cnt=1;
a;b; //一共有10件;
2a;2b;
4a;4b;
3a;3b;
优化参考代码
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值