清北学堂(2019 4 30 ) part 3
今天总的讲些算法,会了的话...看上去好厉害的样子:
1.老朋友动态规划DP:
DP重点:
1.边界条件,开头不需处理的数据,比如斐波那契数列中的第一二项
2.转移方程,后面的项需要根据前面几项求出自身值的方程(等式)
套路:
1.定状态,
2.写方程,
3.敲代码
三种用法:
1.顺着推,
2.倒着推,
3.记忆化搜索,
举个栗子——斐波那契:
1.倒着推:比较简单,只写方程:f[n]=f[n-1]+f[n-2]
2.顺着推:代码
#include<bits/stdc++.h>
using namespace std;
int n;
int f[];
int main(){
scanf("%d",&n);
f[]=;
f[]=;
for(int i=;i<n;i++){
f[i+]+=f[i];
f[i+]+=f[i];
}
cout<<f[n]<<endl;
return ;
}
中间核心部分思想在于最新一项去更新后项,因为由递归公式可得当前f[a]只对f[a+1],f[a+1]产生贡献,而倒着推思想在于用已经推过的值去更新最新一项。
3.记忆化搜索:代码:
#include<bits/stdc++.h>
using namespace std;
int f[];
bool vis[]; //用这个bool数组记录是否推过
inline int dfs(int n){
if(n==) return ;
if(n==) return ;
if(vis[n]) return f[n];
f[n]=dfs(n-)+dfs(n-);
return f[n];
}
int n;
int main(){
scanf("%d",&n);
printf("%d\n",dfs(n));
return ;
}
听说记搜能做出来的动规题,前两种一定能做出来...
分类:
1.数位dp
按照十进制每一位dp,自己写的代码(用动规思想写出的伪高精...):
#include<bits/stdc++.h>
using namespace std;
int xn[],xm[];
int n,m;
int v[];
int main(){
scanf("%d%d",&m,&n);
int tn=,tm=;
while(n>){
xn[tn++]=n%;
n/=;
}
while(m>){
xm[tm++]=m%;
m/=;
}
for(int i=tn-;i>=;i--)
v[i]=v[i+]*+xn[i]-xm[i];
printf("%d",v[]+);
return ;
}
大佬的:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int f[][],z[],l,r;
int solve(int x){
int n=;
while(x){
z[n]=x%;
x/=;
n++;
}//存一下x的十进制表示
n--;
memset(f,,sizeof(f));//要做两个动态规划
f[n+][]=;
for(int i=n;i>=;i--)
for(int j=;j<=;++j){
if(j==){
for(int k=;k<=;++k)
f[i][]+=f[i+][j];
}
else{
for(int k=;k<=z[i];++k){
if(k==z[i]) f[i][]+=f[i+][j];
else f[i][]+=f[i+][j];
}
}
}
return f[][]+f[][];
} int main(){
cin>>l>>r;
cout<<solve(r)-solve(l-)<<endl;
return ;
}
主要思想是分类讨论,讨论每次处理位数是否相等
2.树形dp
例题:求n个节点的树有几个节点(exm?!)
我其实想用前向星遍历求结果来着,还是练练dp吧,
主要思想:
根据子树考虑
每个叶节点的子树节点个数为1,非叶节点的为所有子树的节点数+1(自身)
伪代码:
inline void dfs(int p){
for(int i=tail[p];i;i=ed[i].next){
dfs(ed[i].to);
f[p]+=f[ed[i].to];
}
f[p]++;
}
大概正确吧...
树的直径:
给定一棵树,树中每条边都有一个权值,树中两点之间的距离定义为连接两点的路径边权之和。树中最远的两个节点之间的距离被称为树的直径,连接这两点的 路径被称为树的最长链。后者通常也可称为直径,即直径是一个数值概念,也可代指一条路径
现给一棵树,求其直径
思路:设f[p][0]为p点的最长路,f[p][1]为p点的次长路,分别保存。
需根据子树推导,对每个节点进行讨论,对于叶节点,其没有子树,故无法进行讨论,对于其他节点,则讨论其子树,寻找每个子节点的最长路及次长路,然后 按照方程取:
f[p(当前节点)][0]=max(f[p1(子节点1)][0],f[p2][0],f[p3][0],..........,f[pn][0])+1
f[p(当前节点)][1]=max(f[p1(子节点1)][0],f[p2][0],f[p3][0],.....(加特判不算上一步中取到的点).....,f[pn][0])+1 //因为要去最长路径,所以显然要取最长路径,而不是 次长路,此处容易误认为次长路需从次长路中选。
每次处理时用一个变量“sum”取max来维护路长总和,以保证结果一定是最长最优,毕竟难免出现以下这种鬼图的存在...(绘图网站:???)

所以根节点并不一定是最长路径(直径)经过的点,所以要对每个点进行处理,万一直径的根节点在哪个深山老林里...
3.状压dp(听说是最难的)
一般空间O(n2*2n)
时间O(2n*n)
一般接受n<=20.
(顺便说一下:n<=1000,O(n2))
(n<=100,O(n3))
(n<=105,O(n log n))
(n<=106,O(n))
(n<=12,不要考虑复杂度了上暴搜吧)
TSP问题:
平面上有n个点,问把每个点都走一次的最短路径,并且只能为链,不能为树(更不能是图),如下:

状压(状态压缩),用一个数表示一个集合,比如表示上图的路径
用二进制实现,如下:
对于7 6 5 4 3 2 1,保存路径状态为1 4 6
即为0 1 0 1 0 0 1,
因每个元素对于一个状态来说只有在其中或不在两种状态,可用1与0表示,而对于不同元素
其对应二进制位有独特的位置与权值,所以每一种状态都有唯一的十进制数与其对应
其状态用f[s][i]表示,s为路径压缩结果,即已经走过的点的集合对应十进制数,j为当前停留点
4.区间dp
从区间中枚举断点,合并左右,找最优方案
例题:
合并石子
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=,inf=0x7fffffff/;
int f1[maxn][maxn],f2[maxn][maxn];
int a[maxn],sum[maxn],n,ans1,ans2;
int main(){
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
a[i+n]=a[i];
}
for(int i=;i<=n*;i++){
sum[i]=sum[i-]+a[i];
f2[i][i]=;
f1[i][i]=;
}
for(int l=;l<=n;l++){
for(int i=;i<=*n-l+;i++){
int j=i+l-;
f1[i][j]=inf;
f2[i][j]=;
for(int k=i;k<j;k++){
f1[i][j]=min(f1[i][j],f1[i][k]+f1[k+][j]);
f2[i][j]=max(f2[i][j],f2[i][k]+f2[k+][j]);
}
f1[i][j]+=sum[j]-sum[i-];
f2[i][j]+=sum[j]-sum[i-];
}
ans1=inf;
ans2=;
for(int i=;i<=n;i++){
ans1=min(ans1,f1[i][i+n-]);
ans2=max(ans2,f2[i][i+n-]);
}
}
cout<<ans1<<endl<<ans2;
return ;
}
5.其他(没有套路,只能自己推转移方程)
肥肠常烤非常常考
例题:数字三角形(终于有道做过的了QAQ)
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath> //怀念不用万用文件头的日子
using namespace std;
int n;
int v[][];
int ans=;
int main(){
cin>>n;
for(int i=;i<=n;i++)
for(int j=;j<=i;j++)
cin>>v[i][j];
for(int i=;i<=n;i++)
for(int j=;j<=i;j++)
v[i][j]=max(v[i-][j-],v[i-][j])+v[i][j]; //因为每项只会“被”左上一项或上面一项产生贡献,只考虑那两项
for(int i=;i<=n;i++)
ans=max(ans,v[n][i]);
cout<<ans;
return ;
}
例题*改
对于每项v[i][j]%m,求其最大
多开一个维度,[k],k表示%m剩下的值,dp方程如下:
if(f[i-1][j-1][(k-a[i][j])%m]||f[i-1][j][(k-a[i][j])%m])
f[i][j][k]=true; //这里f数组为bool,结果直接输出k
清北学堂(2019 4 30 ) part 3的更多相关文章
- 清北学堂2019.8.10 & 清北学堂2019.8.11 & 清北学堂2019.8.12
Day 5 杨思祺(YOUSIKI) 今天的难度逐渐上升,我也没做什么笔记 开始口胡正解 今天的主要内容是最小生成树,树上倍增和树链剖分 最小生成树 Prim 将所有点分为两个集合,已经和点 1 连通 ...
- 清北学堂2019.7.18 & 清北学堂2019.7.19
Day 6 钟皓曦 经典题目:石子合并 可以合并任意两堆,代价为数量的异或(^)和 f[s]把s的二进制所对应石子合并成一堆所花代价 枚举s的子集 #include<iostream> u ...
- 清北学堂2017NOIP冬令营入学测试P4745 B’s problem(b)
清北学堂2017NOIP冬令营入学测试 P4745 B's problem(b) 时间: 1000ms / 空间: 655360KiB / Java类名: Main 背景 冬令营入学测试 描述 题目描 ...
- 清北学堂2017NOIP冬令营入学测试 P4744 A’s problem(a)
清北学堂2017NOIP冬令营入学测试 P4744 A's problem(a) 时间: 1000ms / 空间: 655360KiB / Java类名: Main 背景 冬令营入学测试题,每三天结算 ...
- 济南清北学堂游记 Day 1.
快住手!这根本不是暴力! 刷了一整天的题就是了..上午三道题的画风还算挺正常,估计是第一天,给点水题做做算了.. rqy大佬AK了上午的比赛! 当时我t2暴力写挂,还以为需要用啥奇怪的算法,后来发现, ...
- 清明培训 清北学堂 DAY1
今天是李昊老师的讲授~~ 总结了一下今天的内容: 1.高精度算法 (1) 高精度加法 思路:模拟竖式运算 注意:进位 优化:压位 程序代码: #include<iostream>#in ...
- 7月清北学堂培训 Day 3
今天是丁明朔老师的讲授~ 数据结构 绪论 下面是天天见的: 栈,队列: 堆: 并查集: 树状数组: 线段树: 平衡树: 下面是不常见的: 主席树: 树链剖分: 树套树: 下面是清北学堂课程表里的: S ...
- <知识整理>2019清北学堂提高储备D2
简单数据结构: 一.二叉搜索树 1.前置技能: n/1+n/2+……+n/n=O(n log n) (本天复杂度常涉及) 2.入门题引入: N<=100000. 这里多了一个删除的操作,因此要 ...
- <知识整理>2019清北学堂提高储备D3
全天动态规划入门到入坑... 一.总概: 动态规划是指解最优化问题的一类算法,考察方式灵活,也常是NOIP难题级别.先明确动态规划里的一些概念: 状态:可看做用动态规划求解问题时操作的对象. 边界条件 ...
随机推荐
- PHP - 闭包Closure和lambda function
现在的语言没有闭包简直都不好意思说出来. 想要了解闭包是什么,那么就必须知道匿名函数.其实看起来他们其实差不多一个意思. 见php RFC一句话: End of 2007 a patch was ...
- 两个不同vim之间复制内容
常规想法是打开两个vim,然后进行yy和p操作,但是实践证明根本是不行的.此时,我们需要分割窗口,然后就可以复制粘贴了.步骤如下: 假设我要把srv.c文件的readline函数整体复制到cli.c文 ...
- 全文搜索技术—Lucene
1. 内容安排 实现一个文件的搜索功能,通过关键字搜索文件,凡是文件名或文件内容包括关键字的文件都需要找出来.还可以根据中文词语进程查询,并且支持多种条件查询. 本案例中的原始内容就是磁盘上的文件 ...
- 解剖Nginx·模块开发篇(5)解读内置非默认模块 ngx_http_stub_status_module
1 Background ngx_http_stub_status_module 是一个 Nginx 的内置 HTTP 模块,该模块可以提供 Nginx 的状态信息.默认情况下这个模块是不被编译进来的 ...
- jQuery autocomplete -默认
<!doctype html> <html> <head> <meta name="content-type" content=" ...
- shiro 实现 网站登录记住我功能 学习记录(四)
在很多网站都有在登录的时候,比如说记住我 几天之内 只要再此打开这个网站,都不需要再登录的情况: 1.前台JSP增加 单选框:记住我 如 2.在处理登录的 Controller 代码中增加接收这个参 ...
- 花了好几个小时的奇葩Mat为0问题
问题 1. Mat mserMat = adaptive_image_from_points(contour, rect); CCharacter character; character.setCh ...
- VMWare windows找不到microsoft软件许可条款
提示如下错误: windows找不到microsoft软件许可条款.请确保安装源有效,然后重新启动安装. 解决方案: 把该虚拟机中的系统硬件配置中的软盘去掉. 程序员的基础教程:菜鸟程序员
- 如何启动jdeveloper中集成的weblogic
1>运行jdeveloper,打开运行日志,入下图,日志最开始的红框部分就是打开weblogic的命令,将此命令复制出来执行即可打开weblogic 程序员的基础教程:菜鸟程序员
- ChainOfResponsibilityPattern(23种设计模式之一)
参考书籍:设计模式-可复用面向对象软件基础(黑皮书) 目的:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系.将这些对象连成一条链,并沿这条链传递该请求,直到有一个对象处理它为止 ...