知识储备: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. MyBatis:学习笔记(1)——基础知识

    MyBatis:学习笔记(1)--基础知识 引入MyBatis JDBC编程的问题及解决设想 ☐ 数据库连接使用时创建,不使用时就释放,频繁开启和关闭,造成数据库资源浪费,影响数据库性能. ☐ 使用数 ...

  2. bootstrap学习笔记之基础导航条 http://www.imooc.com/code/3111

    基础导航条 在Bootstrap框中,导航条和导航从外观上差别不是太多,但在实际使用中导航条要比导航复杂得多.我们先来看导航条中最基础的一个--基础导航条. 使用方法: 在制作一个基础导航条时,主要分 ...

  3. Django学习笔记(基础篇)

    Django学习笔记(基础篇):http://www.cnblogs.com/wupeiqi/articles/5237704.html

  4. C#学习笔记(基础知识回顾)之值类型与引用类型转换(装箱和拆箱)

    一:值类型和引用类型的含义参考前一篇文章 C#学习笔记(基础知识回顾)之值类型和引用类型 1.1,C#数据类型分为在栈上分配内存的值类型和在托管堆上分配内存的引用类型.如果int只不过是栈上的一个4字 ...

  5. C#学习笔记(基础知识回顾)之值传递和引用传递

    一:要了解值传递和引用传递,先要知道这两种类型含义,可以参考上一篇 C#学习笔记(基础知识回顾)之值类型和引用类型 二:给方法传递参数分为值传递和引用传递. 2.1在变量通过引用传递给方法时,被调用的 ...

  6. C#学习笔记(基础知识回顾)之值类型和引用类型

    一:C#把数据类型分为值类型和引用类型 1.1:从概念上来看,其区别是值类型直接存储值,而引用类型存储对值的引用. 1.2:这两种类型在内存的不同地方,值类型存储在堆栈中,而引用类型存储在托管对上.存 ...

  7. MAVEN学习笔记之基础(1)

    MAVEN学习笔记之基础(1) 0.0 maven文件结构 pom.xml src main java package resource test java package resource targ ...

  8. mybatis学习笔记之基础复习(3)

    mybatis学习笔记之基础复习(3) mybatis是什么? mybatis是一个持久层框架,mybatis是一个不完全的ORM框架.sql语句需要程序员自己编写, 但是mybatis也是有映射(输 ...

  9. mybatis学习笔记之基础框架(2)

    mybatis学习笔记之基础框架(2) mybatis是一个持久层的框架,是apache下的顶级项目. mybatis让程序将主要精力放在sql上,通过mybatis提供的映射方式,自由灵活生成满足s ...

  10. Java学习笔记之---基础语法

    Java学习笔记之---基础语法 一. Java中的命名规范 (一)包名 由多个单词组成时,所有字母小写(例如:onetwo) (二)类名和接口 由多个单词组成时,所有单词首字母大写(例如:OneTw ...

随机推荐

  1. 做网站用UTF-8还是GB2312?

    经常我们打开外国网站的时候出现乱码,又或者打开很多非英语的外国网站的时候,显示的都是口口口口口的字符, WordPress程序是用的UTF-8,很多cms用的是GB2312. ● 为什么有这么多编码? ...

  2. Linux:grub密码设置与修改

    grub密码设置与修改 默认GRUB启动参数可以的进入单用户模式从而修改root密码,如果想要给GRUB菜单设置密码,可以修改/etc/grub.conf文件 (/boot/grub/grub.con ...

  3. React-Native进阶_7.TextInput的使用实现搜索功能

    前面使用TabBar 实现了底部tab标签,通过stackNavigator 实现了页面跳转,接下来,使用TextInput 来实现一个搜索功能. TextInput 属性比较多,不一一介绍,具体可以 ...

  4. JDK 1.8之 HashMap 源码分析

    转载请注明出处:http://blog.csdn.net/crazy1235/article/details/75579654 构造函数 Node hash put treeifyBin get re ...

  5. 通过反编译让SpecFlow支持多层属性值的验证

    需求:在使用SpecFlow时,我希望能对目标对象所关联的对象属性进行验证,但SpecFlow(Version 1.9.0)无法实现.如图中红框,可以对专户所属的金融机构的名称进行验证. 反编译步骤 ...

  6. IDEA中项目统一编码格式设置

    统一UTF-8编码设置 第一处 File-settings-Editor-File Encodings 第二处 File-Other settings-Default settings 第三处 tom ...

  7. springmvc+mybatis+redis实现查询插入操作

    最近在学习redis,虽然现在还不是很熟练.不过可以进行简单的框架整合开发. IDE:我使用的是IDEA.springmvc+spring+mybatis的整合这个我就不多说了,下面我们先进行这块的整 ...

  8. LOJ2362. 「NOIP2016」蚯蚓【单调队列】

    LINK 思路 良心来说这题还挺思维的 我没看题解也不知道要这样维护 把每次斩断的点分别放进两个队列里面 因为要维护增长,所以可以让新进队的节点来一个负增长? 是不是就好了? 然后很容易发现因为在原始 ...

  9. LOJ6039. 「雅礼集训 2017 Day5」珠宝【决策单调性优化DP】【分治】【思维好题】

    LINK 懒得搬题面 简要题意:n个物品,每个物品有一个价格和一个吸引力,问你对于\(i \in [1,k]\),花费i的价格能得到的最大吸引力 其中价格的范围很小,在\([1,300]\)范围内 思 ...

  10. BZOJ3209 花神的数论题 【组合数学+数位DP+快速幂】*

    BZOJ3209 花神的数论题 Description 背景 众所周知,花神多年来凭借无边的神力狂虐各大 OJ.OI.CF.TC …… 当然也包括 CH 啦. 描述 话说花神这天又来讲课了.课后照例有 ...