知识储备:dp入门

好了,完成了dp入门,我们可以做一些稍微不是那么裸的题了。

dp基础,主要是做题,只有练习才能彻底掌握。


洛谷P1417 烹调方案

分析:由于时间的先后会对结果有影响,所以c[i]*b[j]>c[j]*b[i]为条件排序,然后再01背包。

洛谷P1387 最大正方形

分析:用dp[i][j]来表示以a[i][j](正方形数组)为右下角最后一个数的正方形边长,a数组可以直接用dp数组代替掉。

 #include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=;
int dp[maxn][maxn];
int min_a(int a,int b,int c)
{
return min(min(a,b),min(b,c));
}
int main()
{
int n,m,ans=-;
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
scanf("%d",&dp[i][j]);
for(int i=;i<=n;i++)
{
for(int j=;j<=m;j++)
{
if(dp[i][j]>=)
{
dp[i][j]=min_a(dp[i-][j],dp[i-][j-],dp[i][j-])+;
}
}
}
for(int i=;i<=n;i++)
{
for(int j=;j<=m;j++)
ans=max(ans,dp[i][j]);
}
printf("%d",ans);
return ;
}

洛谷P1006 传纸条

分析:拿到题我不假思索地写了一份 单次最大好心值+dfs路径还原标记+单次最大好心值,然而发现,第一次最大好心值的路线把第二次堵死了。。。

好吧,正解是双线程,dp[k][i][j]表示走了k步,两份纸条横坐标分别是i,j时的好心最大值。

安利一发别人博客,讲得很透彻:http://www.cnblogs.com/OIerShawnZhou/p/7492555.html

 #include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=;
int dp[*maxn][maxn][maxn],a[maxn][maxn],go[maxn][maxn];
//dp[k][i][j]走了k步,两份纸条横坐标分别是i,j时的好心最大值
int max_a(int a,int b,int c,int d)
{
return max(max(a,b),max(c,d));
}
int main()
{
int m,n,ans=;
scanf("%d%d",&m,&n);
for(int i=;i<=m;i++)
for(int j=;j<=n;j++)
scanf("%d",&a[i][j]);
for(int k=;k<n+m;k++)//步数
{
for(int i=;i<=k;i++)
{
for(int j=;j<=k;j++)
{
dp[k][i][j]=max_a(dp[k-][i][j],dp[k-][i][j-],dp[k-][i-][j],dp[k-][i-][j-])+a[i][k-i+]+a[j][k-j+];
if(i==j) dp[k][i][j]-=a[i][k-i+];//重复了
}
}
}
printf("%d",dp[n+m-][m][m]);
return ;
}

洛谷P1282 多米诺骨牌

分析:拿到题有点懵,但仔细想想,这好像也算是01背包,可以把翻转每个骨牌得到的点数差看做一件物品(记住,点数不带绝对值),但会出现数组下标为负数的情况,这个时候把 N 看做为0,N-1就是-1,N+1就是1

  dp[i][j]:前i张牌使得上一行点数之和为j的最小方法数

普通版:

 #include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn=;
const int N=maxn*,INF=;
int dp[maxn][*N],a[maxn],b[maxn];//dp[i][j]:前i张牌使得上一行点数之和为j的最小方法数
int main()
{
int n,minnum=INF,k=;
scanf("%d",&n);
for(int i=;i<=n;i++)
{
scanf("%d%d",&a[i],&b[i]);
}
for(int i=;i<maxn;i++)
for(int j=;j<*N;j++)
dp[i][j]=INF;
dp[][N]=;
for(int i=;i<=n;i++)
{
for(int j=-N;j<=N;j++)
{
int dis=a[i]-b[i];//有正有负,故而开数组要开2*N,下面j+N同理
dp[i][j+N]=min(dp[i-][j+dis+N]+,dp[i-][j-dis+N]);//翻或不翻
}
}
for(int i=;i<=N;i++)
{
minnum=min(dp[n][N-i],dp[n][N+i]);
if(minnum!=INF)
{
printf("%d",minnum);
return ;
}
}
return ;
}

滚动数组优化:

 #include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn=;
const int N=maxn*,INF=;
int dp[][*N],a[maxn],b[maxn];//dp[i][j]:前i张牌使得上一行点数之和为j的最小方法数
int main()
{
int n,minnum=INF,k=;
scanf("%d",&n);
for(int i=;i<=n;i++)
{
scanf("%d%d",&a[i],&b[i]);
}
for(int i=;i<;i++)
for(int j=;j<*N;j++)
dp[i][j]=INF;
dp[][N]=;
for(int i=;i<=n;i++)
{
for(int j=-N;j<=N;j++)
{
int dis=a[i]-b[i];//有正有负,故而开数组要开2*N,下面j+N同理
dp[i&][j+N]=min(dp[(i-)&][j+dis+N]+,dp[(i-)&][j-dis+N]);//翻或不翻
}
}
for(int i=;i<=N;i++)
{
minnum=min(dp[n&][N-i],dp[n&][N+i]);
if(minnum!=INF)
{
printf("%d",minnum);
return ;
}
}
return ;
}

洛谷P1880 石子合并

分析:曾经的noi系列。石子合并问题分好几种情况。

这题是环形的,且只能合并相邻的两堆,那么我们把石子数组展开,如[1,2,3,4,5] -> [1,2,3,4,5,1,2,3,4,5],这样进行处理,就能将环形转换成直线。

转换完之后,就可以用dp做了,dp的解释详见代码。这题数据过得去,时间是 O(n3) 不然要用平行四边形优化。

安利一发acdreamer的博客,把石子合并问题讲的很清楚http://blog.csdn.net/acdreamers/article/details/18039073

 #include <cstdio>
#include <algorithm>
using namespace std;
int sum[],mins[][],maxs[][],s[][];//dp[i][j]=i~j的最大得分
int main()
{
int a,n,minnum=,maxnum=-minnum;
scanf("%d",&n);
for(int i=;i<=n;i++)
{
scanf("%d",&sum[i]);
sum[i+n]=sum[i];
s[i][i]=i;
s[i*][i*]=i;
}
for(int i=;i<=*n;i++) sum[i]+=sum[i-]; //前缀和
for(int l=;l<=n;l++)//区间长度
{
for(int i=;i+l<=*n;i++)//开始的端点
{ int j=i+l;//结束的端点
maxs[i][j]=-;mins[i][j]=-*maxs[i][j];
for(int k=i;k<j;k++)
{
maxs[i][j]=max(maxs[i][j],maxs[i][k]+maxs[k+][j]+sum[j]-sum[i-]);
mins[i][j]=min(mins[i][j],mins[i][k]+mins[k+][j]+sum[j]-sum[i-]);
}
}
}
for(int i=;i<=n;i++)//因为是环形的,可从任意两堆间分开,所以需要枚举一遍起点从1~n
{
maxnum=max(maxs[i][i+n-],maxnum);
minnum=min(mins[i][i+n-],minnum);
}
printf("%d\n%d",minnum,maxnum);
return ;
}

洛谷P1108 低价购买

分析:第一问还是很简单的,求最长下降子序列。第二问要计算方案数量,还要判重。

用t[i]表示前i个股票的不同方案个数,可以得出,如果存在dp[j]==dp[i] && a[j]==a[i]方案就是重复的,所以就把t[i]赋为0,如果f[i]==f[j]+1,那么i可以从j转移,所以t[i]+=t[j]。最后统计和即可。

 #include <cstdio>
#include <algorithm>
using namespace std;
int dp[],a[],t[];//t,计算出现次数的dp
int main()
{
int ans=-,n,k=,res=;
scanf("%d",&n);
for(int i=;i<=n;i++) scanf("%d",&a[i]);
for(int i=;i<=n;i++)
{
dp[i]=;
for(int j=;j<i;j++)
{
if(a[j]>a[i]) dp[i]=max(dp[i],dp[j]+);
}
ans=max(ans,dp[i]);
}
for(int i=;i<=n;i++)
{
if(dp[i]==) t[i]=;//如果无法转移则为1
for(int j=;j<i;j++)
{
if(dp[j]==dp[i]- && a[i]<a[j])//判前继 判可以为下一个数
{
t[i]+=t[j];//转移
}
else if(dp[i]==dp[j]&&a[i]==a[j]) t[j]=;//判重
}
}
for(int i=;i<=n;i++)
{
if(dp[i]==ans) res+=t[i];
}
printf("%d %d",ans,res);
return ;
}

【专章】dp基础的更多相关文章

  1. 【学习笔记】dp基础

    知识储备:dp入门. 好了,完成了dp入门,我们可以做一些稍微不是那么裸的题了. dp基础,主要是做题,只有练习才能彻底掌握. 洛谷P1417 烹调方案 分析:由于时间的先后会对结果有影响,所以c[i ...

  2. hdu 2089 不要62 (数位dp基础题)

    不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  3. poj 2955 Brackets (区间dp基础题)

    We give the following inductive definition of a “regular brackets” sequence: the empty sequence is a ...

  4. DP基础(线性DP)总结

    DP基础(线性DP)总结 前言:虽然确实有点基础......但凡事得脚踏实地地做,基础不牢,地动山摇,,,嗯! LIS(最长上升子序列) dp方程:dp[i]=max{dp[j]+1,a[j]< ...

  5. 树形dp基础

    今天来给大家讲一下数形dp基础 树形dp常与树上问题(lca.直径.重心)结合起来 而这里只讲最最基础的树上dp 1.选课 题目描述 在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程 ...

  6. poj2642 The Brick Stops Here(DP基础题)

    比基础的多一点东西的背包问题. 链接:POJ2642 大意:有N种砖,每种花费p[i],含铜量c[i],现需要用M种不同的砖融成含铜量在Cmin到Cmax之间(可等于)的砖,即这M种砖的含铜量平均值在 ...

  7. UVA103 dp基础题,DAG模型

    1.UVA103 嵌套n维空间 DAG模型记忆化搜索,或者 最长上升子序列. 2.dp[i]=max( dp[j]+1),(第i个小于第j个) (1) //DAG模型记忆化搜索 #include< ...

  8. hdu 1561 The more, The Better(树形dp,基础)

    The more, The Better Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Oth ...

  9. hdu1114 Piggy-Bank (DP基础 完全背包)

    链接:Piggy-Bank 大意:已知一只猪存钱罐空的时候的重量.现在的重量,已知若干种钱的重量和价值,猪里面装着若干钱若干份,求猪中的钱的价值最小值. 题解: DP,完全背包. g[j]表示组成重量 ...

随机推荐

  1. java TreeSet应用

    这篇是紧接着上一篇而写的,具体的实现TreeSet中有序的第二中方法 首先新建一个类,此类就是用于集合中存放的对象 然后定义一个类,实现Comparator中的CompareTo()方法 最后一个测试 ...

  2. Web.py 框架学习笔记 - URL处理

    最近由于工作需要开始学习基于python的web应用框架web.py.为了方便学习,将学习心得逐日记下以便日后复习. URL 模板: web.py提供了一套url处理的模板,在python工程中,只需 ...

  3. [置顶] 基于FPGA的VGA简易显存设计&NIOS ii软核接入

    项目简介 本项目基于Altera公司的Cyclone IV型芯片,利用NIOS II软核,2-port RAM与时序控制模块,实现64*48分辨率的显存(再大的显存板载资源m9k不够用) 实现效果如下 ...

  4. TitleLayout——一个Android轻松实现标题栏的库

    TitleLayout 多功能.通用的.可在布局或者使用Java代码实现标题栏: 支持沉浸式状态栏: 支持左侧返回按钮不需要手动实现页面返回: 支持左侧按钮,中间标题,右边按钮点击 左侧支持图片+文字 ...

  5. 201521123109《java程序设计》第八周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容. 1.2 选做:收集你认为有用的代码片段 2. 书面作业 本次作业题集集合 List中指定元素的删除(题目4-1 ...

  6. 201521123035《Java程序设计》第七周学习总结

    1. 本周学习总结 以你喜欢的方式(思维导图或其他)归纳总结集合相关内容. 参考资料: XMind 2. 书面作业 1.ArrayList代码分析 1.1 解释ArrayList的contains源代 ...

  7. 201521123011 《java程序设计》 第7周学习总结

    1. 本周学习总结 参考资料: XMind 2. 书面作业 1.ArrayList代码分析 1.1 解释ArrayList的contains源代码 1.2 解释E remove(int index)源 ...

  8. 201521123008 《Java程序设计》 第九周学习总结

    1. 本周学习总结 2. 书面作业 本次PTA作业题集异常 1.常用异常 题目5-1 1.1 截图你的提交结果(出现学号) 1.2 自己以前编写的代码中经常出现什么异常.需要捕获吗(为什么)?应如何避 ...

  9. 201521123016《Java程序设计》第14周学习总结

    1. 本周学习总结 2. 书面作业 1. MySQL数据库基本操作 建立数据库,将自己的姓名.学号作为一条记录插入.(截图,需出现自己的学号.姓名) 在自己建立的数据库上执行常见SQL语句(截图) - ...

  10. 多线程面试题系列(5):经典线程同步 关键段CS

    上一篇提出了一个经典的多线程同步互斥问题,本篇将用关键段CRITICAL_SECTION来尝试解决这个问题.本文首先介绍下如何使用关键段,然后再深层次的分析下关键段的实现机制与原理.关键段CRITIC ...