U175308 队列、栈、链表、递归、有向无环图、拓扑序、 Dijsktra、 二叉树【笔记】

题目背景

# ### ·$queue$(队列) ·$push$——在队尾加入一个元素 ·$pop$——在队头弹出一个元素 ·$front$——返回队头元素,但不删除 ·$back$——返回队尾元素,但不删除 ·$empty$——如果队为空返回true,否则返回false ·$size$——返回队内元素的数量 ### ·$stack$(栈) ·相比队列,无法获取栈底元素,获取栈顶元素改为$top()$即可 ·—————————————————— ·**链表$ list list1$(创建)** ·**头文件:$$** ·**创建一个链表的迭代器:$list ::iterator$ 迭代器名** ·头部添加一个元素t:$push$$_$$front(t)$ ·尾部添加一个元素t:$push$$_$$back(t)$ ·删除第一个元素:$pop$$_$$front()$ ·删除最后一个元素:$pop$$_$$back()$ ·返回指向第一个元素的迭代器:$begin()$ ·返回指向末尾元素的迭代器:$end()$ ·插入一个元素到$list$中:$insert()$ ·删除一个元素:$erase()$ ·从$list$删除元素:$remove()$ ·返回$list$的元素个数:$size()$ ·返回$list$是否为空,空为$true:empty()$ ·删除所有元素:$clear()$ ·—————————————————— ### ·从前往后输出链表元素 ```cpp list 链表名; list ::iterator 迭代器名 = 链表名.begin(); for (迭代器名 = 链表名.begin();迭代器名 != 链表名.end();迭代器名++){ printf("%d ",*迭代器名); } ``` ### ·添加 ```cpp 链表名.insert(迭代器名,要添加的元素) (若迭代器指向开头,插入开头,若指向末尾,插入末尾) ``` ### ·删除($erase$) ```cpp 链表名.erase(迭代器名) (若迭代器指向开头,删除开头,若指向末尾,删除末尾) ``` ### ·删除($remove$) ```cpp 链表名.remove(要删除的元素t) (删除链表中所有为t的元素) ``` ·—————————————————— ### ·递归 ·**定义**:在函数运行的过程中自己调用自己。 ·**条件**: ·$1、$递归在运行中必须要有退出条件或者有运行条件。 也就是递归的边界。 ·$2、$递归在每次调用自己的时候都必须要靠近边界。 ---

题目描述

# $★$ ### 有向无环图($DAG$) ·**有向**图。 ·**无**环。 ·重边:两点之间有多条边连接(大于或等于$2$)。 ·自环:一条边的起点终点是一个点。 **有向无环图常常用来表示物体之间的依赖关系。** $G$:图的简称。 $V$:点的集合。 $E$:边的集合。 设$G =(V,E)$是一个有向无环图且$|V| = n$。设$v_1,v_2,……v_n$是图上点的一个排列,若此排列满足:对于图$G$上每一有向边$(u,v)$都有$u$排在$v$之前,则称$v_1$,$v_2$,……$v_n$是图$G$上点的**一个拓扑序**。$(topological ordering)$。一般来说**拓扑序不唯一**。通常把求有向无环图的点的拓扑序称为**对有向无环图进行拓扑排序。** ## 图的性质 · **$★$无向图中,顶点的度的和等于边数的$2$倍。** ·**无向图中,度为奇数的顶点的数量一定是个偶数!** ·**有向图中,顶点的出度的和等于顶点的入度的和等于边数。** --- ## 图的概念 ### 连通性 **首先**,它是这个无向图的一个连通子图 。**(保证连通)** **其次**,他不是这个无向图的其他连通子图的子图 。**(保证极大)** --- ### 一些特殊的图 ·**完全图:** 每对顶点间都有边的无向图 ·**二分图:** 每条边的两个顶点分别来自有顶点集合$V$划分得到的两个子集$V_1、V_2$的无向图 。 --- ### 拓扑序的性质 从点$u$可以到达的点一定排在$u$之后。 ### 有向图 以点$u$为端点的边分成两类:$u$的出边和$u$的入边。 类似地定义$u$入度和$u$的出度。 ### 车站分级 建模:有向无环图。 目标:有向无环图上最长路径的长度。 递推:设$f(u)$为从点$u$出发的最长路径的长度。$f(u) = 1 + max(v)$是$u$的邻点 边界条件:若$u$的出度为零,$f(u)=0$。 复杂度分析:朴素建图方式有$500×500×1000$ 对每一个带编号的函数算出它的最简形式。  $M$  $(p_1,v_1),(p_2,v_2),……,(p_k,v_k)$ 对单个加的效果汇总: $Q$次函数调用里,对于一个特定函数的所有调用的效果里,加的一部分前面的系数。 --- ## 最短路 **最短路径的性质:负边与负回路。** --- ## $Dijsktra$算法流程 **条件:没有负边**。$★$ 1、 存图,初始化$d[ ]$,起点为$0$,其余为$inf$。 2、 选择$d[ ]$值最小**且**未被标记红色的点$x$,确定$d[x]$。 3、 标记$x$为红色,通过$x$**松弛**邻接点。 4、 重复$2$直到**没有可选的点**。 --- ## [题目传送门](https://www.luogu.com.cn/problem/P4779) ## 代码 ```cpp #include using namespace std; // 相当于 pair 这个类型起个外号 p,在这个程序里写 p,就会认为是 pair typedef pair p; const int N = 1e5 + 10; struct node { int v, w; }; vector G[N]; // 邻接表存图 int n, m, s; // 顶点数,边数,起点 int d[N]; // d[i]:起点到顶点 i 的最短路径 bool vis[N]; // 顶点是否已经确定从起点开始的最短路径 void Dijkstra(int s) { // 初始化 memset(d, 0x3f, sizeof d); priority_queue q; // 存的是(最短路径,顶点) q.push({0, s}); // 起点入队 d[s] = 0; // 起点到起点的距离是 0 while(!q.empty()) { p t = q.top(); q.pop(); // pair 是一个结构体,第一个成员 first,第二个成员叫 second int u = t.second; // u 是我们选中的最短路径的顶点(结构体成员的访问) if(vis[u]) continue; // u 如果顶点 u 已经确定了最短路径,跳过 vis[u] = true; // u 确定了最短路径 for(int i = 0; i < G[u].size(); i++) { // 找到 u 的所有邻居 int v = G[u][i].v, w = G[u][i].w; if(!vis[v] && d[u] + w < d[v]) { // v 经过 u 过来的路径更短 d[v] = d[u] + w; // 松弛 v 的最短路径 q.push({d[v], v}); } } } } int main(){ cin >> n >> m >> s; for(int i = 1; i v cin >> u >> v >> w; G[u].push_back({v, w}); } Dijkstra(s); // 以 s 为起点到所有顶点的最短路径 for(int i = 1; i T; while(T--) { init(); // 初始化函数 cin >> n >> m; for(int i = 1; i v cin >> u >> v >> w; G[u].push_back({v, w}); // u--w-->v if(w >= 0) G[v].push_back({u, w}); // v--w-->u } if(SPFA(1)) cout > k; for (int i = 1;i > u >> v >> w; dp[u][v] = w; } Floyd(); for (int i = 1;i > u >> v; if (dp[u][v] < 0x3f3f3f3f) cout

输入格式

# ## 欧拉回路 **欧拉回路**:图$G$中的一个**包含所有边**的**简单回路**成为欧拉回路。 **欧拉路径**:图$G$中的一个**包含所有边**的**简单路径**成为欧拉路径。 --- ## 欧拉回路的性质 - 欧拉回路**一定包含**欧拉路径$!$$!$$!$ ### - $★$除了不同的起点和终点外,都要求有成对的出入边。 --- ### 拓展:汉密尔顿$(Hamilton)$回路 --- --- ## 拓扑排序:$Kahn's$ 算法 $1、$**初始化一个队列**来暂存入度为$0$的点。 $2、$**遍历整个图**,将其中入度为$0$的顶点**入队**。 $3、$当队**不空**的时候: $(1)$**取出队首元素**,将其插入当前的到的拓扑序列的末端。 $(2)$遍历它的**每条出边**,删除,如果对应的终点的入度为$0$,则**将它入队**。 $4、$返回得到的**拓扑序列**。**(如果长度不够,说明有环)** $★$ --- ## 代码 ```cpp #include using namespace std; const int N = 1e6 + 10; vector G[N]; // 存图 vector ans; // 存拓扑排序 int n, m; // 顶点数,边数 int inD[N]; // 每个顶点的入度 void TopoSort() { queue q; for(int i = 1; i v 这条边) if(inD[v] == 0) q.push(v); } } } int main() { cin >> n >> m; for(int i = 1; i v cin >> u >> v; G[u].push_back(v); inD[v]++; // v 的入度加 1 } TopoSort(); // 拓扑排序 if(ans.size() < n) cout n >> m; for(int i = 1; i v cin >> u >> v; G[u].push_back(v); outD[u]++; // u 的出度加 1 inD[v]++; // v 的入度加 1 } TopoSort(); // 拓扑排序(目的是求出以每个点为终点的路径条数) int ans = 0; // 最大食物链的数量(总的有多少条食物链,多少条路径) for(int i = 1; i

输出格式

说明/提示

想要通过么? 输出“hello 敢问高姓大名”就不能通过了!