有兴趣的朋友可以去我的洛谷博客康康哦qwq
特别特别感谢:
lmpp大佬牺牲自己宝贵时间,为我没有脾气的耐心讲解。
lmpp大佬的博客:墙裂建议进去康一康!
还有gmq、gbf同学,感谢你们的鼓励与支持!!
did教给我知识真是太强了!!
没有他们就没有这篇博客,我也会比现在蒻上 i n f inf inf倍。
提示:
本博客公开, 但“例题部分”仅记录的是本人认为较有意义添加的题或者是本人的知识盲区。 我会以知识点为经,算法为纬,在知识点开头加入模板题并附有代码,有的时候会写一点小提示,即 tips: \mathfrak\color{CornflowerBlue}\colorbox{Lavender}{tips:} tips:。
在我自己掌握特别不好的题目/知识点旁会加以 ! \color{Red}\colorbox{Yellow}{!} ! 的标记。
所有题号以BSOJ为准。
有什么错误纰漏的直接QQ+洛谷私信+讨论区留言,我真的超级需要您的反馈的qwq。
希望能您能从这份清单中找到您的一些知识漏洞并把他们补起来!
更新信息
2020.3.29 1.0版本,开始新的篇章。知识点记录至拓扑排序模板题。
2020.3.30 && 2020.3.31 2.0版本,爆肝完所有知识点。
拓扑排序:
tips1: \mathfrak\color{CornflowerBlue}\colorbox{Lavender}{tips1:} tips1:
拓扑排序的基本知识:
-
在图论中,拓扑排序是一个有向无环图(DAG)的所有顶点的线性序列,该序列必须满足下面两个条件:
- 每个顶点出现且只出现一次。
- 若存在一条从顶点A到顶点B的路径,那么在序列中顶点A出现在顶点B的前面。
-
有向无环图(DAG)才有拓扑排序,非DAG图没有拓扑排序一说。 [ 1 ] ^{[1]} [1]
-
拓扑排序的操作方法:
- 从DAG图中选择一个 没有前驱(即入度为零) 的顶点并输出。
- 从图中删除该顶点和所有以它为起点的有向边。
- 重复1和2直到当前的DAG图为空或当前图不存在无前驱的顶点为止。后一种情况说明有向图中必然存在环。
-
通常,一个DAG图可以有一个或多个拓扑序列。
[ 1 ] ^{[1]} [1]:拓扑排序之所以只能针对于DAG图,就是因为它有每次取出入度为0的顶点的操作,如果有环,则环中的顶点不存在入度为0的点,无法进行拓扑排序。
tips2: \mathfrak\color{CornflowerBlue}\colorbox{Lavender}{tips2:} tips2:
关于拓扑排序的应用
拓扑排序一般很少有单独针对该知识点的题,但是在关键路径和平常的其他例题的辅助操作中却发挥着重要作用。所以掌握好拓扑排序是很重要的事情。
tips3: \mathfrak\color{CornflowerBlue}\colorbox{Lavender}{tips3:} tips3:
本代码按字典序输出的部分:
int j=1; //从第一个点开始查找
while(j<=n&&bein[j])
j++; //统计入度为零的节点
//由于-1的bool值也视作真,所以可以标记为-1
if(j>n) return 0; //如果统计的节点超出了范围n,说明这个图有环
sum[++top]=j; //拓扑序列答案数组统计新答案
//本代码由邻接矩阵实现,按字典序输出,复杂度O(n^2)
#include <iostream>
#include <cstdio>
#define maxn 205
using namespace std;
int bein[maxn]; //bein[i]表示节点i的入度
int a[maxn][maxn]; //邻接矩阵存图
int sum[maxn],top; //拓扑序列答案数组
int n,m;
int TS()
{
for(int i=1;i<=n;i++)
{
int j=1; //从第一个点开始查找
while(j<=n&&bein[j])
j++; //统计入度为零的节点
//由于-1的bool值也视作真,所以可以标记为-1
if(j>n) return 0; //如果统计的节点超出了范围n,说明这个图有环
sum[++top]=j; //拓扑序列答案数组统计新答案
bein[j]=-1; //标记此点已经遍历
for(int k=1;k<=n;k++)
if(a[j][k]) //如果j和k之间有边相连
bein[k]--; //和j相关联的节点删除与j相连的边,即入度--
}
return 1; //如果遍历过程中没有返回过假值,则有解,返回真值
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
a[x][y]=1; //邻接矩阵储存单向边
bein[y]++; //输入是从x到y的连线,所以是y的入度增加
}
if(TS()) //如果有解
for(int i=1;i<=n;i++)
cout<<sum[i]<<" "; //则输出节点的答案数组
else
cout<<"no solution"<<endl; //无解输出"no solution"
return 0;
}
最小生成树
-
最小生成树:在一张带权的无向连通图中,各边权和为最小的一颗生成树即为最小生成树。
简单讲:找出连接所有点的最低成本路线。
-
最小边原则 [ 2 ] ^{[2]} [2]:图中权值最小的边(如果唯一的话)一定在MST上。
-
唯一性 [ 3 ] ^{[3]} [3]:一颗最小生成树上,如果各边的权都不相同,则最小生成树是唯一的。
[ 2 ] ^{[2]} [2]、