Day 1
今天是zhx讲的搜索Orz….
1. 关于搜索
搜索的基本形式
- dfs && bfs
什么样的题目可以搜索
解的可能空间是指数级别的大小
我们需要其中的最优解,或者总共可行解的空间大小
解的可能空间
可行解的空间
三类基本的搜索问题
可行解问题
最优解问题
解数量问题
2.搜索技巧
0.判断使用DFS还是BFS
使用BFS的条件:
求一个状态到另一个状态的最小步数
状态可压缩,并且内存能够接受或者无需判重
状态的层数不会太深
满足以上三个条件,可以使用BFS
否则使用DFS
1.状态的表示与判重
搜索的本质是探索解空间的所有状态
从一个状态到另外一个状态的过程叫做转移
如果状态有重复我们就有可能需要判重
状态的表示:将所有会对结果有影响的信息记录下来,即可表示为一个状态
状态的判重:stl(set,map),hash
2.通用剪枝方法
最优解问题:超过当前解直接 GG
可行解问题:???
解数量问题:重复性的利用(记忆化搜索)
通用的一些方法:
排除不可能的分支
优先走玄学上更好的分支
随机化
3.卡时
蒟蒻的想法:有输出总比 TLE 好
卡时可以得分从 0 变成
≥0
#include<ctime>
#include<cstdio>
using namespace std;
int t;
void dfs(...) {
if(clock()-t>=850) {
printf(your ans);
return;
}
.....
return;
}
int main() {
t=clock();
....
return 0;
}
4.双向BFS
使用前提:
知道终止状态
终止状态的逆转移可写
- 终止状态逆转移状态数与顺转移状态数同阶
5.分支界定
BFS的拓展
每次找到一个状态,把该状态所有状态扩展出来,加入搜索队列
与BFS不同地方在于,每次取出的状态不一定是最前面的状态
你可以取最后面的,或者用优先队列取最小的
6.A*
zhx感觉没有什么琴梨用的玩意儿
定义 c 为最终最优代价,
f(s) 为起始状态到状态 s 的最优代价,g(s) 为从 s 到终止状态的最优代价,则c=f(s)+g(s) 搜索的时候我们只知道 f(s) ,如果设 h(s) 为对 g(s) 的估计
结合分支界定,优先 f(s)+h(s) 最优的状态
考虑以下几种情况:
h(s)<g(s) ,一定能搜到最优解,但是速度很慢
h(s)=g(s) ,一定能搜到最优解,速度比 h(s)<g(s) 快
h(s)>g(s) ,不一定能搜到最优解,但速度最快
7.迭代加深搜索
无良出题人卡BFS内存怎么办?
利用迭代加深,限定DFS搜索深度
两种迭代加深的方法:
枚举深度
二分深度
#include<cstdio>
using namespace std;
int d;
int dfs(...int depth) {
if(depth==d+1) {
...;
return;
}
....
return;
}
int main() {
for(d=..;d<=..;d++)
dfs(....,1);
int l=..,r=..;
while(l<=r) {
d=l+r>>1;
dfs(....,1);
}
return 0;
}
2.problem
洛谷 P1379 八数码难题:
bfsA*经典题,题解暂坑戳这里洛谷 P1219 八皇后:dfs经典题,题解戳这里
八大金刚问题:并没有找到这是个什么东西,所以划掉它吧qwqNOIP 2009 靶形数独:贪心+dfs,题解
暂坑戳这里NOIP 2011 Mayan游戏:模拟+dfs,题解
暂坑戳这里zhx的题:FlowFree
正解好像是插头dp,不过有搜索的数据
有兴趣的自己做吧,反正我是不会做..数据可以和我要qwq
Day 2
说好的数据结构然而成了讲题大会…
数据结构没什么好讲的,我们直接讲题好了 ——zhx
1. NOIP阶段必须要会的数据结构
我把我会的都划掉了,相信我划掉的大家肯定都会..
数组、链表
这两个要是不会直接退役算了
队列、栈、堆
我会用stl,而且还会手写模板类…
并查集
唯一需要注意的地方是father的初始化
int Find(int x) {
return father[x]==x?x:father[x]==Find(father[x]);
}
树状数组||
线段树
这两个会一个就好,推荐会线段树
听钟神说了不止一次,数据结构的题90%都是线段树
树树上LCA
倍增、树剖、tarjan都不会….我可真是够笨的
DFS序列、括号序列
dfs序有时候可以代替树剖,把树上问题转换成链上问题,还是挺好用的
听括号序列的时候睡着了...
启发式合并
小的集合并到大的上,没了
单调队列
滑动窗口是道不错的入门题,会了那道题应该就会单调队列了
前缀和
这个东西不应该人人都会?
其实我不会二维的
二分、分治
2. problem
bzoj 2096: [Poi2010]Pilots:堆或者单调队列,题解戳这里
bzoj 2375: 疯狂的涂色:并查集维护区间问题,题解戳这里
bzoj 3333: 排队计划:分块或者线段树,然而…不会,暂坑
HDU 4467 Graph:图的分块…不会,暂坑
bzoj 2529: [Poi2011]Sticks:堆,题解
暂坑戳这里bzoj 3306: 树:dfs序+线段树,题解暂坑,不对是戳这里
HDU 3333 Turing Tree:线段树,
好像漏了这道题..,暂坑
Day 3
alpq654321 讲的第一题钟神Day 2讲了,好尴尬….
1.动态规划
状态设计:
往往是观察在搜索过程中需要用到的参数,所表示的含义往往是“最大”、“最小”、“方案总数”、“0/1”。
转移设计:
思考该状态能够转移到哪些状态,或者该状态由哪些状态转移而来。
注意无后效性!
2. 动态规划的常见优化
前缀和(最大值)优化。
单调队列优化。
数据结构优化(NOIP一般不考)。
NOI:斜率优化,矩阵乘法+快速幂优化,常数优化,四边形不等式优化,优化状态等。
3.单调队列在dp中的应用
个人理解:
首先是最优解问题才能用单调队列
转移的时候是有一段区间相同的区间转移来的,而且 i+1 和 i 相比区间变化并不大
有时候也可以是不连续的几个值(如部分背包问题)
个人感觉看下面的图就可以明白了…
- 欢迎指错qwq
4.problem
NKOJ 2150 广告印刷:因为NKOJ暂时无法注册,而且我没要到数据,暂坑
tyvj P1313 [NOIP2010初赛]烽火传递:经典的单调队列优化dp,题解戳这里
NOI 2005 瑰丽华尔兹:不会做..暂坑
bzoj 2448 挖油:被alpq654321称作终极题目的题我当然不会做啦,暂坑
Day 4
讲的是我比较擅长的图论…
1.图论
1.图的定义
一个图由点的集合与边的集合
(|V|,|E|) 构成。一条连接 u,v 的边用 (u,v) 表示,当 u=v 时存在自环。
在有向图中所有边都是有向的,也就是说 (u,v)≠(v,u)
在无向图中所有边都是无向的,也就是说 (u,v)=(v,u)
定义一个点 v 的入度为
(u,v) 中 u 的个数定义一个点
u 的出度为 (u,v) 中 v 的个数每条边可能存在权值
定义
w1,w2,…,wp 为图的一条路径当且仅当存在 (w1,w2),(w2,w3),…,(wp−1,wp) , () 表示边一条路径称为简单路径,当且仅当 w 互不相同
当图的边没有权值时,路径的长度为边的条数,否则为边权之和
若一条路径
w1=wp ,则我们称这条路径为这个图的一个环对于无向图,若任意两点之间是可达的,我们称这张图是连通的
对于有向图,若任意两点之间互相可达,我们称这张图为强连通。否则若将其变成无向图后这张图是连通的,我们称这张图为弱连通
我们称 A 是
B 的子图,当且仅当 B 的点集包含A 的点集,且 B 的边集包含 A 的边集若此时
A 是强连通的,且不存在一个图 C ,使得A 是 C 的子图且C 强连通,则称 A 是B 的极大强连通分量一个图中若任意两个不同的点 u,v 都存在 (u,v) 与 (v,u) ,则称这个图为完全图。
2.图的表示方式
邻接矩阵
邻接矩阵的优势与劣势?
方便!
快捷!需要 n2 的空间,访问一个点的所有边时时间复杂度为 O(n)
适用于完全图或者稠密图中。
int G[MAXN][MAXN]
void addedge(int u,int v,int w) {
G[u][v]=G[v][u]=w;
return;
}
int u;
for(int v=1;v<=n;v++)
if(G[u][v]) {
....
}
- 邻接表
当图比较稀疏时一般用邻接表,空间复杂度为 O(|V|+|E|)
struct Edge {
int u,v,w,next;
Edge(int u=0,int v=0,int w=0,int next=0):
u(u),v(v),w(w),next(next) {}
};
Edge edge[MAXM];
int head[MAXN],cnt;
void addedge(int u,int v,int w) {
edge[++cnt]=Edge(u,v,w,head[u]);
head[u]=cnt;
return;
}
int u;
for(int i=head[u];i;i=edge[i].next) {
...
}
还有一种用vector存图的,然而我没学过那个….
管你什么图我就用邻接表
3.最大团和最大独立点集
选择一个图中的若干点,若任意两个点之间均有一条边联通,则这些点组成的集合是一个团
最大团即最多的点组成的团
选择一个图中的若干点,若任意两个点之间都没有一条边联通,则这些点组成的集合是一个独立点集
最大独立点集即最多的点组成的独立点集
最大团 =n− 最大独立点集
4.拓扑排序
如果存在一个排列 a1,a2,…,an ,使得在该图中不存在 ai 到 aj 的路径 (i>j) ,我们称这个排列为这个图的拓扑序列
我们每次寻找入度为 0 的点加入序列中。
并将当前点连接的所有边均删除,更新其它点的度数。
由于每条边至多被删除一次。
因此这个时间复杂度是
O(|E|) 的code见下面的练习题吧…
5.最短路
给定一张带边权的图与两个点 u,v ,询问 u 到
v 的所有路径中最短的那条是多少。一般有Floyd、dijkstra,spfa三种算法
Floyd :好简单呐…不写了…
dijkstra
令 dis[i] 表示当前 u 到
i 的最短路是多少。将 dis[u]=0,dis[i]=inf(i!=u)
寻找最小的 dis[x] 且 x 曾经没被找到过。-gg
若
x=v ,输出答案并退出。枚举 x 的所有边,用
dis[x] 去更新其余 dis[] ,回到gg时间复杂度为 n2 ,可以堆优化,然而我不会,GG
使用范围:不存在负权边。
spfa
令 dis[i] 表示当前 u 到
i 的最短路是多少。将 dis[u]=0,dis[i]=inf(i!=u) ,并将 u 加入队列中。
设当前队首为
u ,枚举 u 。 -gg枚举
u 的所有边,用 dis[u] 去更新其余 dis[] ,若 dis[i] 此时被更新且 i 当前不在队列中,将其加入队列。将
u 弹出队列,若此时队列为空,结束,否则返回gg
管你什么图我就用spfa
6.最小生成树
给定一个无向带非负整数边权的图。选择其中若干条边,使得这张图联通,并且要求这些边的边权之和最小。选择的边数一定是 n−1
一般有Prim和Kruskal两种算法
Prim
任选一个点作为一个子图
在原来图中选择一条最短的边,使得这条边一端在当前子图中,另一端不在当前子图中,加入这条边与这个点。重复 n−1 次。
得到最小生成树
code和dijkstra有点像
Kruskal
每次选择一条边权最小且两个端点不连通的边。将其加入进最小生成树中。
重复 n−1 次。
判断是否连通用并查集实现。
管你什么图我就用Kruskal
7.二分图
如果一个无向图 G 中
V 能分成两个点集 A 与B ,且位于 A 中的顶点互相之间没有边,位于B 中的顶点互相之间没有边,则称这个图为二分图。二分图的判定方法
判断有没有奇环,不存在奇环则是二分图
证明?不存在的…
DFS法
利用DFS将这个二分图进行染色,若染色成功,则这个图为二分图,否则不是二分图
并查集法
将每个点A裂成两个点A与A’。
若A与B之间存在边,则连一条A与B’的边,A’与B的边。
若此时A与A’连通,或者B与B’连通,则该图不是二分图。(若连通则必然出现了奇环)
有时间详细写一篇blog
8.二分图最大匹配
在一个二分图中选择最多的边,使得没有任何一个点有连接它的两条边被选择到。
只学了匈牙利算法,而这个算法,这位大哥的blog是再好不过的了
9.搜索树
对一个图从某一点开始进行深度优先搜索。
搜索到的边构成的树称为搜索树。
在这棵树上的边称为树边,其余边称为非树边。
性质:对图求搜索树时,非树边连接的两个端点在搜索树中一定是其中一个点是另一个点的祖先。
10.强连通分量
求无向图的所有强连通分量,:)
给你个微笑自己体会求有向图的所有强连通分量,tarjan
tarjan当然是看 BYvoid 巨佬的blog啦!
其实没写tarjan和匈牙利是因为我懒
2.problem
bzoj 2530: [Poi2011]Party:求一个团,题解戳这里
NOIP 2010 关押罪犯:二分图,并查集都能做,题解暂坑
洛谷 P2341 [HAOI2006]受欢迎的牛:tarjan+缩点,题解戳这里
bzoj 2730: [HNOI2012]矿场搭建:好像和割点有关,题解暂坑
HDU 2647 Reward:拓扑排序,题解戳这里
HDU 1548 A strange lift:按照题意建图,然后跑最短路,题解戳这里
NOIP 2013 货车运输:最大生成树+树上倍增,题解
暂坑戳这里
Day 5
简单列一下知识点…
1.数论
- 模运算
唯一需要注意的是 (a−b)%p
- 快速幂
int poow(int n,int k) {
int ret=1;
for(;k;k>>=1,n*=n)
if(k&1) ret*=n;
return ret;
}
- 线性筛 && 埃拉托色尼筛
代码好长 不贴了
其实可以在我的这篇blog里找到
- gcd && lcm
int gcd(int a,int b) {
return !b?a:gcd(b,a%b);
}
int lcm(int a,int b) {
reurn a/gcd(a,b)*b;
}
- 扩展欧几里得
void exgcd(int a,int b,int &x,int &y) {
if(!b) {
x=1,y=0;
return;
}
exgcd(b,a%b,y,x);
y-=(a/b)*x;
return;
}
压到两行食用更佳
- 中国剩余定理
蛤?
- 欧拉函数 && 欧拉定理
其实也可以在我的这篇blog里找到
- 费马小定理
没错还是这篇blog
- 矩阵乘法
这篇blog里也有
- 组合数学
自行百度 Bing Google吧....
2.problem
NOIP 2013 转圈游戏:快速幂,没了,题解暂坑
bzoj 1477: 青蛙的约会:exgcd,题解暂坑
NOIP 2012 同余方程:exgcd,题解暂坑
poj 1006 生理周期:中国剩余定理,题解暂坑
bzoj 1257: [CQOI2007]余数之和sum:数学题,题解戳这里
poj 2954 Triangle:pick定理+gcd+叉积,题解戳这里
Day 6
字符串弃疗…
Day7
二分和贪心都是根据题目讲的,所以直接贴题目了
1.二分大法
poj 2976 Dropping Tests:分数规划,题解暂坑
poj 2728 Desert King:最优比率生成树,题解暂坑
poj 3621 Sightseeing Cows:最优比率生成环(spfa判正权环),题解暂坑
51nod 1686 第k大区间:二分+取尺法(滑动窗口),题解暂坑
NOIP 2015 跳石头:二分答案,题解暂坑
NOIP 2010 关押罪犯:这题做法怎么这么多…题解暂坑
2.贪心大法
洛谷 P1090 合并果子:贪心+堆,题解暂坑
bzoj 2563: 阿狸和桃子的游戏:贪心,题解暂坑
bzoj 1707: [Usaco2007 Nov]tanning分配防晒霜:依旧贪心,题解依旧暂坑
bzoj 2697: 特技飞行:没错还是贪心,没错题解还是
暂坑戳这里tyvj P1094 矩形分割:同上…
bzoj 1634: [Usaco2007 Jan]Protecting the Flowers 护花:
同上....题解戳这里NOIP 2012 国王游戏:
同上...题解戳这里
Day 8
- 难题选讲还是留在最后吧…..
先把前面的坑填了再说