先来看一下经典的背包问题吧

http://www.cnblogs.com/Kalix/p/7617856.html  01背包问题

https://www.cnblogs.com/Kalix/p/7622102.html   完全背包问题

https://blog.csdn.net/mystery_guest/article/details/51878140      多重背包二进制优化

1.https://cn.vjudge.net/problem/12304/origin    POJ 3176

从上往下走或者右下走找最大总和,也可以不同dp写。

注意动态规划这一步一定是和上一步或下一步有关联的

//dp[i][j]表示走到i,j这步时的最大值
for(i=;i<=n;i++)
{
for(j=;j<=i;j++)
{
dp[i][j]=max(dp[i-][j],dp[i-][j-])+map[i][j];//(i,j)这一步是从(i-1,j)或者(i-1,j-1)走过来的
ans=max(ans,dp[i][j]);
} }

全部代码

#include<stdio.h>
#include<algorithm>
#include<iostream>
using namespace std;
int n,map[][],dp[][];
int ans=; int main()
{
cin>>n;
for(int i=;i<=n;i++)
{
for(int j=;j<=i;j++)
{
cin>>map[i][j];
}
}
int i,j;
for(i=;i<=n;i++)
{
for(j=;j<=i;j++)
{
dp[i][j]=max(dp[i-][j],dp[i-][j-])+map[i][j];
ans=max(ans,dp[i][j]);
} }
cout<<ans;
}

2.https://cn.vjudge.net/problem/30465/origin    POJ 2229

这题是看一个数能用几个不同二次方幂的数和表示

首先来练习一下深搜把,这一开始我没想到还能用深搜,尽管不对,当然可慢啦啦啦啦

#include<stdio.h>
#include<math.h>
#include<iostream>
using namespace std;
int ans;
long long p[];
void dfs(int n,int last)
{
if(n==)
{
ans++;
return;
}
for(int i=;n-p[i]>=;i++)
{
if(p[i]>=last)
dfs(n-p[i],p[i]);
}
}
int main()
{
int n;
for(int i=;i<=;i++)
p[i]=pow(,i);
cin>>n;
dfs(n,);
printf("%d",ans); return ;
}

接下来是dp版的,不知道为啥,还是超时!!!!,但思想要学习下,看懂下面的那个dp更新表就欧克了

dp表假设只有1,然后添加2,然后添加4然后添加8,更新表

#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
long long dp[],p[];
int main()
{
int n; while(scanf("%d",&n)!=EOF)
{
memset(dp,,sizeof(dp));
p[]=dp[]=;
for(int i=;i<=;i++)
{
p[i]=p[i-]<<;
}
for(int i=;i<=;i++)
{
if(p[i]<=n)
{
for(int j=p[i];j<=n;j++)
{
dp[j]=(dp[j]+dp[j-p[i]])%;
}
}
}
/*dp 1 2 3 4 5 6 7//假设输入7
1 1 1 1 1 1 1 1
2 2 2 3 3 4 4
4 4 4 6 6
*/
cout<<dp[n]<<endl;
} }

最后过的是这个,我他喵。。。

#include<iostream>
#include<string.h>
using namespace std;
long long a[];
int main()
{
int n;
a[]=,a[]=;
for(int i=;i<;i++)
{
a[i]=a[i-]+a[i/];
a[i]%=;
}
cin>>n;
cout<<a[n];
}

1.n为奇数,a[n]=a[n-1]
2.n为偶数:
(1)如果加数里含1,则一定至少有两个1,即对n-2的每一个加数式后面 +1+1,总类数为a[n-2]
(2)如果加数里没有1,即对n/2的每一个加数式乘以2,总类数为a[n/2]

3.https://cn.vjudge.net/problem/18264/origin    POJ 2385

题意有两棵树1,2,掉苹果,人一开始在1下,有指定的移动次数,给苹果下落,求最多接到的苹果数

首先想一想,跟平常的题有什么区别

1.人会移动,

2.苹果要判断是否要不移动接到,还是移动接到

3.移动的次数不像是背包问题里的背包容量越多越好,但和背包问题类似

for(int i=;i<=n;i++)
{
dp[i][]=dp[i-][];//第i个苹果,j次移动的最好结果,判断一直不动的情况
if(t[i]==) dp[i][]++; for(int j=;j<=w;j++)
{
if(j%+==t[i]){//判断移动后的位置在哪,如果跟这次下落苹果的位置一样
dp[i][j]=max(dp[i-][j],dp[i-][j-])+;//dp的关键,跟上次的东西有关联,接这个苹果我可以选择i-1个苹果移动相同的次数,然后不动接
                                                  //也可以从另一个苹果树移动过来接
}
else
dp[i][j]=max(dp[i-][j],dp[i-][j-]);
}
}

整体代码

#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
int t[];
int dp[][];
int main()
{
int n,w;
cin>>n>>w;
for(int i=;i<=n;i++)
{
cin>>t[i];
} memset(dp,,sizeof(dp));
for(int i=;i<=n;i++)
{
dp[i][]=dp[i-][];
if(t[i]==) dp[i][]++; for(int j=;j<=w;j++)
{
if(j%+==t[i]){
dp[i][j]=max(dp[i-][j],dp[i-][j-])+;
}
else
dp[i][j]=max(dp[i-][j],dp[i-][j-]);
}
}
cout<<dp[n][w]<<endl;
}

4.https://cn.vjudge.net/problem/16276/origin    POJ 3616

给定时间段,每个时间段有工作效率,每个时间段都要休息,求最大工作量

1.首先想到的是要对这些时间段排序,根据结束时间

2.对他们进行动态规划,具体思想可以参考求一个序列的最大上升子序列

#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
struct node{
int s,e,ef; }x[];
bool cmp(node a,node b){
return a.e<b.e;
}
int dp[];
int main()
{
int a,b,c;
cin>>a>>b>>c;
for(int i=;i<=b;i++)
{
cin>>x[i].s>>x[i].e>>x[i].ef;
x[i].e+=c;
}
sort(x+,x++b,cmp);
memset(dp,,sizeof(dp));
int ans=;
for(int i=;i<=b;i++)
{
dp[i]=x[i].ef;
for(int j=;j<i;j++)
{
if(x[i].s>=x[j].e)
{
dp[i]=max(dp[i],dp[j]+x[i].ef);//判断选这个或者不选这个,根据工作量大小
}
}
ans=max(ans,dp[i]);
}
cout<<ans; }

牛客多校第二场a题

一个人可以走一步或者跳x步,但不能连着跳,问到这个区间里有几种走法

考虑两种状态  对于这一点,我可以走过来,前面是怎么样的我不用管,也可以跳过来但是,跳过来必须保证前一步是走的

dp[i][0]表示i这一步是走过来的dp[i][1]表示i这一步是跳过来的

#include<iostream>
#include<bits/stdc++.h>
using namespace std;
long long dp[][];
long long mod=1e9+;
long long ans[];
int main()
{
int n,w;
cin>>n>>w;
dp[][]=;
for(int i=;i<=;i++)
{
dp[i][]=(dp[i-][]+dp[i-][])%mod;
if(i>=w) dp[i][]=dp[i-w][]%mod;
} for(int i=;i<=;i++)
{
ans[i]=(dp[i][]+dp[i][]+ans[i-])%mod;
}
//for(int i=1;i<=10;i++)
//cout<<ans[i]<<endl; while(n--)
{
long long l,r;
cin>>l>>r;
cout<<(ans[r]-ans[l-]+mod)%mod<<endl;
}
return ;
}
[POJ-3280]

给一串字符串,添加字母或者去掉字母使其变成回文串,不过有代价  ,让代价最小

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
using namespace std;
int n,m,dp[][],t[],k,p;
int main()
{
char s[],a[];
while(cin>>n>>m)
{
memset(dp,,sizeof(dp));
cin>>a;
for(int i=;i<n;i++)
{
cin>>s>>k>>p;
t[s[]-'a']=min(k,p);
}
for(int i=;i<m;i++)
{
for(int j=i-;j>=;j--)
{
dp[j][i]=min(dp[j+][i]+t[a[j]-'a'],dp[j][i-]+t[a[i]-'a']);
if(a[i]==a[j])
dp[j][i]=min(dp[j+][i-],dp[j][i]);
}
}
cout<<dp[][m-]<<endl; }
}

hdu 2844 Coins

:Tony想要买一个东西,他只有n中硬币每种硬币的面值为a[i]每种硬币的数量为c[i]要买的物品价值不超过m

多重背包的二进制优化

#include <iostream>
#include <cstring>
#define INF 0x3f3f3f3f
using namespace std;
int f[],a[],c[];
int n,m; //m背包的总容量、v物品的体积、w物品的价值
void OneZeroPack(int m,int v,int w) //0-1背包
{
for(int i=m;i>=v;i--)
f[i]=max(f[i],f[i-v]+w);
} //m背包的总容量、v物品的体积、w物品的价值
void CompletePack(int m,int v,int w) //完全背包
{
for(int i=v;i<=m;i++)
f[i]=max(f[i],f[i-v]+w);
} //m背包的总容量、v物品的体积、w物品的价值、num物品的数量
void MultiplePack(int m,int v,int w,int num)//多重背包
{
if(v*num>=m)
{
CompletePack(m,v,w);
return ;
}
int k=;
for(k=;k<=num;k<<=)
{
OneZeroPack(m,k*v,k*w);
num=num-k;
}
if(num)
OneZeroPack(m,num*v,num*w);
} int main()
{
while(cin>>n>>m)
{
if(n==&&m==) break;
for(int i=;i<n;i++)
cin>>a[i];
for(int i=;i<n;i++)
cin>>c[i];
for(int i=;i<=m;i++) f[i]=-INF;
f[]=;
for(int i=;i<n;i++)
{
MultiplePack(m,a[i],a[i],c[i]);
}
int sum=;
for(int i=;i<=m;i++)
if(f[i]>) sum++;
cout<<sum<<endl;
}
return ;
}

hdu 2089

http://acm.hdu.edu.cn/showproblem.php?pid=2089

算是数位dp的入门吧

求n到m之间数字中没有4和62(连着)的个数

#include <algorithm>
#include <iostream>
using namespace std; int dp[][]; void init(){
dp[][] = ;//dp[0][1-9] = 1都可以
for(int i = ; i <= ; i++)
for(int j = ; j < ; j++)//i位
for(int k = ; k < ; k++)//i-1位
if(j != && !(j == && k == ))
dp[i][j] += dp[i-][k];
} int solve(int n){
int d[];
int len = ; while(n > ){//数组保存
d[++len] = n%;
n /= ;
} d[len + ] = ; int ans = ; for(int i = len; i >= ; i--){ for(int j = ; j < d[i]; j++){
if(j != && !(d[i+] == && j == )) ans += dp[i][j];//求和
} if(d[i] == || (d[i] == && d[i+] == )) break;//判出 } return ans;
} int main()
{ int r, l;
init();
while(cin>>l>>r){
if(r + l == ) break; cout<<solve(r+) - solve(l)<<endl;
}
return ;
}

POJ - 3046

题目大意:蚂蚁牙黑,蚂蚁牙红:有A只蚂蚁,来自T个家族,分别记为ant[i]个。同一个家族的蚂蚁长得一样,但是不同家族的蚂蚁牙齿颜色不同。任取n只蚂蚁(S <= n <= B),求能组成几种集合?

状态:dp[i][j]:前i种中选j个可以组成的种数

决策:第i种选k个,k<=ant[i] && j-k>=0

转移:dp[i][j]=Σdp[i-1][j-k]

#include<stdio.h>
#include<string.h>
int dp[][];
int num[];
int main(){
int n,m,a,b,x;
while(scanf("%d%d%d%d",&n,&m,&a,&b)!=EOF){
memset(num,,sizeof(num));
for(int i=;i<m;i++){
scanf("%d",&x);
num[x]++;
}
memset(dp,,sizeof(dp));
for(int i=;i<=num[];i++) dp[][i]=;
for(int i=;i<=n;i++){
for(int j=;j<=b;j++){
for(int k=;k<=num[i];k++){
if(j>=k) {
dp[i][j]+=dp[i-][j-k];
dp[i][j]%=;
}
}
}
}
int ans=;
for(int i=a;i<=b;i++){
ans+=dp[n][i];
ans%=;
}
printf("%d\n",ans);
}
return ;
}

还有一种

dp[i][j] = dp[i-1][j] + dp[i][j-1] - dp[i-1][j-ant[i]-1]

#include<iostream>
using namespace std;
#define MOD 1000000
int T, A, S, B;
int ant[];
int dp[][];
int ans;
int main()
{
scanf("%d%d%d%d", &T, &A, &S, &B);
for (int i = ; i <= A; i++)
{
int aa;
scanf("%d", &aa);
ant[aa]++;
}
dp[][] = dp[][] = ;
for (int i = ; i <= T; i++)
for (int j = ; j <= B; j++)
if (j - ant[i] - >= ) dp[i % ][j] = (dp[(i - ) % ][j] + dp[i % ][j - ] - dp[(i - ) % ][j - ant[i] - ] + MOD) % MOD; //在取模时若出现了减法运算则需要先+Mod再对Mod取模,防止出现负数(如5%4-3%4为负数)
else dp[i % ][j] = (dp[(i - ) % ][j] + dp[i % ][j - ]) % MOD;
for (int i = S; i <= B; i++)
ans = (ans + dp[T % ][i]) % MOD;
printf("%d\n", ans);
return ;
}

DP动态规划练习的更多相关文章

  1. Day 5 笔记 dp动态规划

    Day 5 笔记 dp动态规划 一.动态规划的基本思路 就是用一些子状态来算出全局状态. 特点: 无后效性--狗熊掰棒子,所以滚动什么的最好了 可以分解性--每个大的状态可以分解成较小的步骤完成 dp ...

  2. (转)dp动态规划分类详解

    dp动态规划分类详解 转自:http://blog.csdn.NET/cc_again/article/details/25866971 动态规划一直是ACM竞赛中的重点,同时又是难点,因为该算法时间 ...

  3. 【模板整合计划】DP动态规划

    [模板整合计划]DP动态规划 一:[背包] 1.[01背包] 采药 \([P1048]\) #include<algorithm> #include<cstdio> int T ...

  4. DP动态规划学习笔记——高级篇上

    说了要肝的怎么能咕咕咕呢? 不了解DP或者想从基础开始学习DP的请移步上一篇博客:DP动态规划学习笔记 这一篇博客我们将分为上中下三篇(这样就不用咕咕咕了...),上篇是较难一些树形DP,中篇则是数位 ...

  5. 树形DP——动态规划与数据结构的结合,在树上做DP

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是算法与数据结构的第15篇,也是动态规划系列的第4篇. 之前的几篇文章当中一直在聊背包问题,不知道大家有没有觉得有些腻味了.虽然经典的文 ...

  6. [原]POJ1141 Brackets Sequence (dp动态规划,递归)

    本文出自:http://blog.csdn.net/svitter 原题:http://poj.org/problem?id=1141 题意:输出添加括号最少,并且使其匹配的串. 题解: dp [ i ...

  7. 5. Longest Palindromic Substring(最长回文子串 manacher 算法/ DP动态规划)

    Given a string s, find the longest palindromic substring in s. You may assume that the maximum lengt ...

  8. 摆花 (DP动态规划)

    2012_p3 摆花 (flower.cpp/c/pas) 时间限制: 1 Sec  内存限制: 128 MB提交: 17  解决: 10[提交][状态][讨论版][命题人:外部导入] 题目描述 3. ...

  9. DP动态规划学习笔记

    作为考察范围最广,考察次数最多的算法,当然要开一篇博客来复习啦. 子曰:温故而知新,可以为师矣 我复习DP时有一些自己对DP的理解,也就分享出来吧. ——正片开始—— 动态规划算法,即Dynamic ...

随机推荐

  1. ARM Linux 内核 panic 之cache 一致性 ——cci-400 cache一致互联

    ARM Linux 内核 panic 之cache 一致性 ——cci-400 cache一致互联 CCI-400 集合了互联和一致性功能,有 2 个 ACE slave 接口和 3 个 ACE-Li ...

  2. 关于ucos操作系统中如何从邮箱中提取出消息

    问题提出? 定义两个任务,task1,task2,想task1用OSMboxPost,task2用OSMboxPend定义了一个邮箱Mbox1=OSMboxCreate(括号里面应该怎么写?)还有具体 ...

  3. js和jquery对象的相互转换

    在使用jquery的过程中发现很多需要将jquery对象转成js对象的例子. Query 对象是通过 jQuery 包装DOM 对象后产生的对象.jQuery 对象是 jQuery 独有的,其可以使用 ...

  4. jsp页面运行的步骤以及原理

    1.jsp页面在服务器端的执行步骤: 1)将jsp页面翻译成java文件 2)编译  java-class 3)执行返回结果(html页面)给客户端. 2.jsp页面运行的原理: jsp在服务器端运行 ...

  5. 多python版本下,使用pip安装第三方库

    说明:win10系统,先安装有Python3.5.2,后又安装了Python2.7.13(并重命名了Python27文件夹下python.exe为python2.7.13.exe),试图使用pip安装 ...

  6. Python 学习笔记(九)Python元组和字典(二)

    什么是字典 字典是另一种可变容器模型,且可存储任意类型对象. 字典的每个键值 key=>value 对用冒号 : 分割,每个键值对之间用逗号 , 分割,整个字典包括在花括号 {} 中 键必须是唯 ...

  7. 一站式学习Redis 从入门到高可用分布式实践

    1:redis 是用c语言来实现的,速度快 持久化 单线程 复杂的数据类型有bitmap和hyperloglog和geo地理信息2:高可用.分布式 v2.8开始支持Redis-Sentinel(哨兵) ...

  8. 汇编中PSP是什么?为什么一般cs比ds大10h

    一般来说,PSP是256个字节,当程度生成了可执行文件以后,在执行的时候,先将程序调入内存, 这个时候DS中存入程序在内存中的段地址,紧接着是程序的一些说明,比如说程序占用多大空间等 等,这就是PSP ...

  9. H3C Telnet 配置-01

    Telnet 配置管理方法是网络工程师和网络管理员使用最广泛的一种设备访问控制方法,它通过局域网或广域网实现本地或远程的访问控制,但是它的实验必须要求首先对设备进行初始化配置,否则用户无法正常登录和访 ...

  10. 【读书笔记 - Effective Java】03. 用私有构造器或者枚举类型强化Singleton属性

    实现Singleton(代表本质上唯一的系统组件)的三种方法: 1. 保持私有构造器,导出公有的静态成员,客户端访问该类的唯一实例. 2. 保持私有构造器,公有的成员是静态工厂方法. 3. 单元素的枚 ...