当前位置: 首页 > 编程日记 > 正文

Day 3 上午

内容提要:

动态规划

数位DP

树形DP

区间DP


动态规划

斐波那契数列
f(0)=0,f(1)=1,......,f(n)=f(n-1)+f(n-2)
0,1,1,2,3,5,8,13......
他和动态规划有什么关系?
首先,他有一个边界条件,就是f(0)=0,f(1)=1,相当于它不是从正无穷到负无穷都有定义的数列
像这种规定好的条件,我们把它叫做 边界条件(不依赖其他值就能直接得到)
f(n)=f(n-1)+f(n-2)
f(n)的值依赖于前两项斐波那契数列的值
这个式子就叫做动态规划中的 转移方程
每一个f(0),f(1),....,f(n)就叫做动态规划中的 状态
无后效性等价于有向无环图(DAG)这里先暂时不提
对于一个动态规划题,我们只需要确定状态,边界条件,转移方程,剩下的就只剩下写代码了

有三种不同的写法
1.顺着推
2.倒着推
(名字起得好随意,其实就是递推和递归)
3.记忆化搜索

 

int n,f[233];int main()
{cin>>n;f[0]=0;f[1]=1;for(int a=2;a<=n;a++){f[a]=f[a-1]+f[a-2];}cout<<f[n];
}

 

数组f代表状态,f(i)代表第i项
先定义边界状态
然后写转移方程
这是逆着推

for(int a=0;a<n;a++)
{f[a+1]+=f[a];f[a+2]+=f[a];
}
cout<<f[n];


顺着推
想f(a)会影响那些斐波那契的值

int dfs(int n)
{if(n==0) return 0;if(n==1) return 1;return dfs(n-1)+dfs(n-2);
}
int main()
{cin>>n;cout<<dfs(n)<<endl;return 0;
}

逆着推是当你算f(a)的时候,你要去算他
顺着推是当你算好f(a)的时候,你用f(a)去更新别人
两种写法在某些时候会有复杂度的区别

记忆化搜索
记忆化搜索的核心是搜索

以斐波那契数列为例:

如果我们直接搜索,搜到1就返回1,搜到0就返回0的话,这个代码的复杂度是f(f(n)),因为f(n)是由一个一个f[1]=1累加起来的

斐波那契通项公式是指数级的,所以当n很大时,复杂度就gg

记忆化:

int f[n];bool suan_le_mei[n];int dfs(int n)
{if(n==0) return 0;if(n==1) return 1;if(suan_le_mei[n]) return f[n];suan_le_mei[n]=true;f[n]=dfs(n-1)+dfs(n-2);
}
int main()
{cin>>n;cout<<dfs(n)<<endl;return 0;
}


因为当你算f(n)时要算f(n-2),算f(n-1)时也要算f(n-2),但是由于f(n-2)的值不变,所以它重复了
记忆化搜索就是保证每一个f(n)在搜索中只被算一次
所以我们两个数组
一个表示第i项的值
一个表示第i项有没有被算过
为了避免重复计算,我们要先看它有没有被算过
一旦算过就直接返回这一项的值
否则就先把它标记为算过,再dfs前两项计算这一项的值
这样写的话复杂度就变成了O(n),因为每个值只被算了一次
一般来说它用不上,但是要知道怎么写
矩阵优化的话复杂度就变成了O(log n) 链接

常见的动规种类:
数位DP
树形DP
状压DP
区间DP
其他DP(其他是个什么鬼呦~)

还有两种NOIP中基本不会涉及
插头DP
博弈论DP

一般来说每一年NOIP中至少会出一道DP题
但是令人吃鲸的是:最大概率考的是其他DP(鬼才出题人)

先来看四种有套路的
数位DP:
看一个非常简单的题
读入两个正整数l,r,问你从l到r中有多少个正整数
答案显然是r-l+1
但是我们要挑战自己,所以来个数位dp
[l,r]数的个数=[0,r]数的个数-[0,l-1]数的个数
我们就把问题化成了求[0,x]这段区间之间有多少个数
把x的十进制表示写出来
X=XnXn-1....X0
数位dp的核心思想就是按照十进制位从高到低一位一位进行dp
刚才的问题等价于看有多少个v满足0≤v≤x
V=VnVn-1...V0
如果有Vn=0就说明有前导0
给VnVn-1...V0每一个数填上0~9之间的某一个看有多少方案满足v≤x
数位dp填数的时候是从高往低填的
比如当你填Vn-3时,Vn-2,Vn-1,Vn已经填好了
比较两个数的大小从高往低比较
我们希望填上Vn-3后,v的前四位≤x的前四位
分情况讨论:
1.x前三位>v前三位,此时Vn-3可以填0~9的任何一个数
2.x前三位=v前三位,为了保证填了这一位有v的前四位≤x的前四位,我们能填的数就是0~Xn-3
数位dp的数组一般至少有两个维度
f[i][j]
i表示已经填到了第i位
j取值要么是0,要么是1
j=0:表示x的前i位数>v的前i位数
j=1:表示x的前i位数=v的前i位数
f[i][j]表示这种情况下的方案数
转移:我们去枚举第i-1位填什么,然后就转移到f[i-1][j']上
这就是数位dp的一个核心思路

代码奉上:

 1 int solve(int x)
 2 {
 3     int n=0;
 4     while(x)
 5     {
 6         z[n]=x%10;
 7         x/=10;
 8         n++;
 9     }
10     n--;
11     
12     memset(f,0,sizeof(f));
13     
14     f[n+1][1]=1;
15     
16     for(int a=n;a>=0;a--)
17     {
18         for(int b=0;b<=1;b++)
19         {
20             if(b==0)
21             {
22                 for(int c=0;c<=9;c++)
23                     f[a][0]+=f[a+1][b];
24             }
25             else 
26             {
27                 for(int c=0;c<=z[a];c++)
28                 {
29                     if(c==z[a]) f[a][1]+=f[a+1][b];
30                     else f[a][0]+=f[a+1][b];
31                 }
32             }
33         }
34     }
35     return f[0][0]+f[0][1];
36 }
37 
38 int main()
39 {
40     cin>>l>>r;
41     cout<<solve(r)-solve(l-1)<<endl;
42     return 0;
43 }

注意这里要进行两次dp,所以进行下一次dp之前要请空数组
我们发现当填第n位时,要从第n+1位转移过来
但是n+1位都是0,所以他们相等
所以我们令f[n+1][1]=1

考虑从第n位到第a+1位是相等还是小于
然后分情况讨论,枚举0和1
如果b=0,第a位就可以填0~9的任何一个数
如果b=1,第a位就可以填0~z[a]之间的数
然后再次讨论填的数是否=z[a]
答案是小于的方案加上等于的方案

Problem 2
求在[l,r]中的数的数位之和

把之前的代码稍微改一下

代码:

int l,r,z;int f[23333][2];
int g[23333][2];
int solve(int x)
{int n=0;while(x){z[n]=x%10;x/=10;n++;}n--;memset(f,0,sizeof(f));memeste(g,0,sizeof(g));f[n+1][1]=1;g[n+1][1]=0;//因为第n+1位是0 for(int a=n;a>=0;a--){for(int b=0;b<=1;b++){if(b==0){for(int c=0;c<=9;c++){f[a][0]+=f[a+1][b];//每一个方案对数位之和贡献一个c g[a][0]+=g[a+1][b]+f[a+1][b]*c;}}else {for(int c=0;c<=z[a];c++){if(c==z[a]) {f[a][1]+=f[a+1][b];g[a][1]+=g[a+1][b]+f[a+1][b]*c;}else {f[a][0]+=f[a+1][b];g[a][0]+=g[a+1][b]+f[a+1][b]*c;}}}}}return g[0][0]+g[0][1];
}int main()
{cin>>l>>r;cout<<solve(r)-solve(l-1)<<endl;return 0;
}

改造改造就好了

Problem 3
求在[l,r]中满足十进制位中相邻两个数字之差至少为2的数有多少个

既然多了一个条件,最直接的方法就是增加一个维度,变成一个三维状态

f[i][j][k]
i和j一样
k表示第i位填了k
保证第i位和第i+1位的差至少为2

洛谷P2657 windy数

树形dp

举一个栗子:
给你一颗n个点的树,问这棵树有多少个点?、
显然是n个点
但是我们要挑战自己,所以我们选择用树形dp

(显然是闲得蛋疼)
对于树形dp来说,这棵树一定会有一个根
不能再往下走的点就是叶子节点
以某个点为根的子树就是它能到达的所有点形成的树

以根节点为根的子树所对应的显然就是整棵树
f[i]代表以i为根的子树有多少个点
如果根节点是1的话,我们最终要求的显然就是f[1]
边界条件?f[leaf]=1 叶子节点所对应的子树大小就是1
显然它是从下往上推的
所以我们在算到p的时候,他下面的都已经被算完了
f[p]=f[son1]+f[son2]+...+f[sonk]+1(k为儿子的个数)
以p为根的子树大小=它所有儿子的子树大小之和+1

伪代码:

int f[233];void dfs(int p)
{for(x is p''s son)//枚举x是p的儿子 
    {dfs(x);f[p]+=f[x]; }f[p]++; 
}int main()
{cin>>n;//点数 read_tree();//读入树//由于它是从下往上,所以我们选用dfsdfs[1];cout<<f[1]<<endl;return 0;
}

又一个栗子:
给你一个n个点的树,求它的直径
直径:在这棵树上找到两个点,使它们的距离最远
考虑一棵子树内的直径怎么算

从一个点走到另一个点的过程尽可能大
树状路径一定是向上走到某一个点,在向下走到某一个点
从一个点向下走两条路,两条路拼起来后形成一条路径
要让这两条路径都尽可能长
也就是从一个点向下走最长和次长的路径拼起来,就是以这个点为拐点的最长路径
f[i][0]代表i向下最长路径的长度
f[i][1]代表i向下次长路径的长度
算一个点的答案,要把它所有儿子的答案整合起来
f[p][0]=max(f[p1][0],f[p2][0],...f[pk][0])+1
假如最大是p2
如果我们把f[p2][0]换成f[p2][1]可以吗?
不行!
因为如果f[p1][0]最长,f[p2][1]次长,就会重复走,这显然是不合法的
我们不如直接把它去掉
f[p][1]=max(f[p1][0],,...f[pk][0])+1

区间dp

洛谷P1880 合并石子
有n堆石子,你只能合并相邻两堆石子
a1,a2,a3,....,an
合并一次 n-1 堆石头
合并两次 n-2 堆石头
求最小代价

合并相邻,把所有的合并为一个:区间dp
状态一定是f[l][r],代表把l和r合并的最小代价

让我们回到这个题
这个题求的是f[1][n]
先定义状态:f[l][r]
边界:f[i][i]=0当你只有一堆石头时,合并代价是0
最后一次合并一定是把两堆石头合并成一堆石头
合并石头并不会改变原本的顺序,所以最后一次合并一定可以找到一条分界线,使得左边为l,右边为r
合并左边:f[l][p] 合并右边:f[p+1][r]
转移方程:f[l][r]=min(f[l][p]+f[p+1][r]+sum[l][r])
思路:枚举断点

代码:

int z[manx],f[maxn][maxn];int main()
{cin>>n;for(int a=1;a<=n;a++)cin>>z[a];//表示石子数memset(f,0x3f,sizeof(f));//初始化为无穷大 for(int a=1;a<=n;a++)f[a][a]=0;//枚举左端点,右端点,断点 for(int l=1;i<=n;l++)//枚举左端点 
    {for(int r=l+1;r<=n;i++)//枚举右端点 
        {for(int p=l;p<r;p++){f[l][r]=min(f[l][r],f[l][p]+f[p+1][r]+sum[l][r]);//左边合并的代价+右边合并的代价+这段区间的石子之和 
            }}}cout<<f[1][n]<<endl; return 0; 
}

石子之和用前缀和计算就好了

代码非常的简单易懂对吧

但是

这是不对的!

(惊不惊喜,意不意外,刺不刺激

为什么呢?

因为它不满足dp的阶段性
因为你算f[1][n]时要用到f[2][n],但它还没有被算过
我们注意到长的区间都是由短的区间拼起来的,所以我们枚举区间长度

int z[manx],f[maxn][maxn];int main()
{cin>>n;for(int a=1;a<=n;a++)cin>>z[a];//表示石子数memset(f,0x3f,sizeof(f));//初始化为无穷大 for(int a=1;a<=n;a++)f[a][a]=0;for(int len=2;len<=n;len++)//枚举区间长度 
    {for(int l=1,r=len;r<=n;l++,r++)//枚举区间位置 
        {for(int p=l;p<r;p++){f[l][r]=min(f[l][r],f[l][p]+f[p+1][r]+sum[l][r]);//左边合并的代价+右边合并的代价+这段区间的石子之和 
            }}}cout<<f[1][n]<<endl; return 0; 
}

复杂度O(n^3)

但是第1堆和第n堆是相邻的
怎么处理?

如果直接在最后一堆后面再加上一个第一堆石头,这样答案就不一定是f[1][n]了
它还有可能是f[2][n+1]
就是min(f[1][n],f[2][n+1])
但是这样a1和a2就不相邻了
在最后再加上a2
这样继续下去,把石子弄成a1,a2,....,an,a1,a2,....,an
ans=min(f[1][n],f[2][n+1],f[3][n+2],f[4][n+3]....)
每次合并两个相邻的东西相当于去掉一条边
只需要合并n-1次,这样的话至少有一条边没有用到,可以看成把这条边断开,就变成了断开的答案
所以我们刚才就是在枚举到底断开哪一条边
仍然是一遍dp,只不过区间变成了两边

转载于:https://www.cnblogs.com/lcezych/p/10794212.html

相关文章:

SpringBoot------添加保存时自动编译插件

1.右键Java项目2.选择“Spring Tools”3.选择“Add Boot DevTools”4.每次使用Ctrl S键时就会自动编译了 实际上是在Pom.xml文件中添加了如下Java包 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring…

设置PLSQ 连接oracle数据库

1 、instantclient_12_1 的设置 配置文件内容 tnsnames.ora # tnsnames.ora Network Configuration File: C:\oracle\product\10.2.0\db_1\network\admin\tnsnames.ora # Generated by Oracle configuration tools.ORCL (DESCRIPTION (ADDRESS (PROTOCOL TCP)(HOST 221.…

《星辰变OL》估计很多人看过这书

瓜瓜小说论坛《星辰变OL》估计很多人看过这书&#xff0c;也估计很多人都不知道这游戏就快开始运行了。 本人2009-2010最期待的游戏了。 咩羊大大你千万注意下&#xff0c;这游戏一有封测&#xff0c;内测一类。一定要给我留个号。 下面看视频。 一定要给我留号啊~咩羊&#xf…

Ubuntu16.04 搭建nexus 私服 学习步骤以及安装maven和git

1、下载安装maven wget https://www-us.apache.org/dist/maven/maven-3/3.6.0/binaries/apache-maven-3.6.0-bin.tar.gz 1、创建maven仓库位置 2、修改setting.xml文件 添加东西如下 export M2_HOME/software/maven/apache-maven-3.6.0 export CLASSPATH$CLASSPATH:$M2_H…

Asp.net(C#)给图片加上水印效果(转自园上的Seven Eleven)

Asp.net(C#)给图片加上水印效果 private void Btn_Upload_Click(object sender, System.EventArgs e) { if(UploadFile.PostedFile.FileName.Trim()!"") { //上传文件 string extension Path.GetExten…

pip install失败报错解决方案

cmd pip install 某些包时报错 pip install Consider using the --user option or check the permissions. 只需要pip install --user package就可以解决转载于:https://www.cnblogs.com/webRobot/p/10799270.html

12.19冲刺总结

第二天冲刺&#xff1a; 昨天完成的任务&#xff1a; 主界面布局 遇到的问题&#xff1a; 登录界面弹窗 今日任务&#xff1a; 主界面编写转载于:https://www.cnblogs.com/mhj666/p/8349629.html

Win2003 防木马、权限设置、IIS服务器安全配置整理

原贴http://hi.baidu.com/zzxap/blog/item/18180000ff921516738b6564.html2009-02-10 10:45一、系统的安装   &#xff11;、按照Windows2003安装光盘的提示安装&#xff0c;默认情况下2003没有把IIS6.0安装在系统里面。&#xff12;、IIS6.0的安装开始菜单—>控制面板—&…

Js面试题(一)--js实现数组去重怎么实现?

方法1、创建一个新的临时数组来保存数组中已有的元素方法2、使用哈希表存储已有元素方法3、使用indexof判断数组元素第一次出现的位置是否为当前位置方法4、先排序再去重第一种方法和第三种方法都使用了indexof()&#xff0c;这个函数的执行机制也会遍历数组第二种使用了哈希表…

使用Maven 打包项目 生成XXX.tar.gz 文件

1、在项目中创建assembly文件夹 创建如图的一个assembly.xml文件 内容如下 <assemblyxmlns"http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"h…

整理了一下SQL Server里面可能经常会用到的日期格式转换方法

select getdate() 2004-09-12 11:06:08.177 举例如下: select CONVERT(varchar, getdate(), 120 ) 2004-09-12 11:06:08 select replace(replace(replace(CONVERT(varchar, getdate(), 120 ),-,), ,),:,) 20040912110608 select CONVERT(varchar(12) , getdate(), 111 ) 2004/…

java使用Cookie判断用户登录情况

1.判断是否登录 public boolean isLogin() {Set<Cookie> cookies this.browser.getCookies();String JSESSIONIDID "JSESSIONID";String sessionIdID "sessionId";String loginID "login";String JSESSIONIDIDValue "";Str…

桌面菜单背景修改

只能修改资源管理器里的右键菜单&#xff0c;即桌面、文件夹和各种文件上的右键菜单&#xff0c;其它如标题栏和任务栏的是没效果的&#xff0c;可惜了。修改其实只是注册了一个dll文件&#xff0c;然后修改这个dll里面的背景图片就可以了。1.首先下载ContextBG.dll。2.然后下载…

全浏览器兼容的DIV拖动效果

测试过下列浏览器 IE6、IE7、IE8、Chrome 5、FF 3.6、Opera 10、Safari 5 拖动效果的脚本网上都有&#xff0c;但网上找到的脚本有个问题 这是在网上随便找的代码(原出处不知道&#xff0c;很多类似代码的文章都没写出处&#xff0c;实在不知道到底出至哪里...) 代码 1 <!DO…

SpringSecurity使用 配置文件 和wen.xml 文件配置

目录 1、web.xml 文件配置 2、spring-security 普通 为使用自己创建的认证类 1、web.xml 文件配置 !-- 配置SpringSecurity的拦截器 --><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring/spring-se…

Echo团队Alpha冲刺随笔 - 第九天

项目冲刺情况 进展 已经进入测试阶段&#xff0c;正在消除系统的bug问题 通过测试&#xff0c;找出了系统中存在的较多bug......体会 测试太重要了&#xff0c;很多原本以为没什么bug&#xff0c;一测就能找到好几个&#xff0c;而且改个bug真的可能新加n多个今日会议内容 黄少…

Windows下配置scrapy需要MVC的14.0版本(转载)

转载于--http://blog.csdn.net/MrWilliamVs/article/details/77130965 杨煜冬煜杨的博客&#xff0c;他的博客比较杂&#xff0c;Java、Python都有--http://blog.csdn.net/yyd19921214 环境依赖于 microsoft visual C 14.0, 仔细看报错后面还写着该C库的下载地址&#xff1b;(但…

关于SQLServer2005的学习笔记——约束、Check、触发器的执行顺序

通常我们认为一条 Insert 就是一个事务&#xff0c;但这个事务是如何执行的呢&#xff1f;如果保障事务执行时该事务的完整性和一致性呢&#xff1f;抛开存储机制、索引、锁等环节&#xff0c;让我们看看约束、 Check 和触发器在这个过程中的先后顺序&#xff0c;或许能加深些对…

Kubernetes集群部署(yum部署)

环境准备 Kubernetes-Master:192.168.37.134 #yum install kubernetes-master etcd flannel -y Kubernetes-node1:192.168.37.135 #yum install kubernetes-node etcd docker flannel *rhsm* -y Kubernetes-node2:192.168.37.146 #yum install kubernetes-node etcd…

完成个人中心—导航标签

个人中心—视图函数带标签页面参数tagapp.route(/usercenter/<user_id>/<tag>)def usercenter(user_id, tag): if tag ‘1: return render_template(usercenter1.html, **context)个人中心—导航标签链接增加tag参数<li role“presentation”><a…

PowerShell 2.0 实践(十二)管理 SQL Server 2008 R2(1)

DBA可以使用的工具很多&#xff0c;对于SQL Server来说&#xff0c;有查询分析器、事件探查器、命令行工具等&#xff0c;其中SQL语句是重中之重&#xff0c;但是PowerShell的出现使得DBA又多了一种选择。 测试脚本下载 本系列所有测试脚本均在Windows Server 2008 R2 DataCent…

Vue.js 学习路线

目录 1、Vue环境搭建 2、绑定数据 绑定对象 循环数组渲染数据 3、Vue 及双向数据绑定 Vue事件介绍 以及Vue中的ref获取dom节点 4、Vue事件 定义方法 执行方法 获取数据 改变数据 执行方法传值 以及事件对象 5、 Vue中创建单文件组件 注册组件 以及组件的使用 6、Vue中组…

企业信息化所面临的问题

企业信息化建设企业信息化所面临的问题 wxwinter 摘要 企业信息化所面临的问题以及对解决这问题的探讨目录 1 企业信息化建设走到今天所面临的问题 1 1.1 一、没有意识到信息化与工业化是一个不可分割的整体 1 1.2 二、系统零散,产生了信息孤岛 1 1.3 三…

windows 10 下部署WCF 一些细节

总体上在IIS中部署一个WCF服务和Win7没有什么区别 但是&#xff0c;如果你使用的是.NET 4.5开发的 WCF服务&#xff0c;而windows10 又安装了.net 4.7 那么你需要注意下面问题 转载于:https://www.cnblogs.com/songr/p/10806615.html

30岁前挣够500万

教你30岁前挣够500万&#xff01;&#xff08;不妨看完&#xff0c;心态会改变。&#xff09; 成功源于自信&#xff01;相信自己。下边每个字都是价值不菲&#xff0c;你认真看了吗&#xff1f;一艘没有航行目标的船&#xff0c;任何方向的风都是逆风1、你为什么是穷人&#x…

查看微码的两种方式hmcaix

转载于:https://www.cnblogs.com/jonathanyue/p/9301212.html

根据传入坐标和图片URL地址对图片进行切图操作、将图片转化成Base64位码

目录 1、根据传入坐标和图片URL地址对图片进行切图操作 2、将图片转化成Base64位编码、根据传入坐标 算出切点坐标 在开发过程的学习记录&#xff0c;此两个工具类主要是对图像的处理&#xff08;切图&#xff09;&#xff0c;对文件的想换转化&#xff0c;将文件转化成字节数…

SQL语句 goto

代码 /*********************求1234......................100的和*******************************/declaresumsmallint,ismallintseti1setsum0label: if(i<100) beginsetsumsumisetii1gotolabel endprintsum 都说不要用goto,可我看了一些经典sql 代码,…

zookeeper 和 dubbo 配置

转载于:https://www.cnblogs.com/tian1993/p/10807996.html

学习总结--团队项目

《一》团队项目 小组成员思维活跃&#xff0c;仅仅在一节课的时间里提出了n个颠覆软件开发界的思维的idea&#xff0c;最后在层层pk最后留下了八个惊世骇俗的想法。其中包括了要重振中国游戏界&#xff0c;打破王者农药的垄断地位要重写的贪吃蛇小游戏和2D游戏&#xff1b;还有…