乱七八糟的图论1

图的基本概念

图是点和边组成的集合体,G=<V,E>;

V是点集

E是边集

有向边,有向图

无向边,无向图

无权、点权、边权、负权

环、自环、重边、有向无环图(DAG)

路径、简单路径:没有经过重复的点、连通

树:n个点n-1条边的连通图、完全图:任何两点间都有一条边(无向图)、竞赛图:将完全图上的每条边定一个方向、基环树:有一个环,其他全是树、仙人掌:可以存在环,但是每一条边,至多只存在于一个环中

图的输入方式

最常见的输入方式是用 1 - N 表示顶点,并逐行给出 M 条边所连接的两点和边权大小。
N M
u1 v1 w1
u2 v2 w2
. . .
um vm wm
如果有点权,一般会用一行 N 个数表示每个点的权值大小。
p1 p2 . . . pn



邻接矩阵是最简单的图存储方式。
对于 N 个点的图,用 N × N 的二维数组记录两点之间是否有边相连,以及边权大小。

空间复杂度 O(N^2)
对于边不存在的情况,可能采用 ∞,也可能使用 0 或 -1 等等特殊值,视具体情况而定。
对于有重边的情况,可能不能完整保留所有边的信息。



邻接表是更为常用的图存储方式。
对每个点 u 用不定长度数组或链表存储所有以其为起点形如< u, v > 的边。
无向图双向边拆分为两条单向边。

不定长数组
链表

空间复杂度 O(N + M)

图的遍历方法:

广度优先搜索bfs 队列

深度优先搜索dfs 栈



广度优先遍历 BFS
用队列实现,按照一定顺序依次访问每个结点。

创建一个包含起点的队列
取出队首结点,将相邻的未入队结点加入队列
重复上一步直到所有结点都被遍历过

适用于无权图上单源最短路问题

深度优先遍历 DFS
用栈(递归函数)实现,按照一定顺序依次访问每个结点。

从起点 s 开始遍历
在遍历到 u 时,递归遍历所有未被访问的相邻结点 v
当遍历 s 的函数退出时,所有结点都被遍历

BFS 和 DFS 是最基础的图的遍历方法,更多的遍历方法基本都是基于此两者

BFS 和 DFS 都可以用来判断图连通,或者求连通子图

两者各有优劣,要根据实际情况选择

结合搜索的知识

三种DFS序

前序遍历

中序遍历

后续遍历

一些简单的例题

例1

1.给定一个有向图,边权为1或2,求单源最短路。

(不能用floyd、dijkstar、spfa等)

开三个队列,首先全部放在距离为0的队列中,然后枚举一个点的所有临点,如果距离为1,扔到距离为1的队列中,如果距离为2扔到距离为2的队列中

创建三个集合, Q0 表示当前层, Q1 表示距离为 1 的层,Q2 表示距离为 2 的层,初始 Q0 = {s}, Q1 =?, Q2 =?

依次取出 Q0 中的点,将其邻点放入对应的 Q1 或 Q2 中

然后Q0 =Q1, Q1 = Q2, Q2 = ?

注意一个点可能和当前层既有长度为 1 的边,又有长度为 2 的边,应当将其加入 Q1 而非 Q2。

例2

给出一个有向图和起点 s,对每条边 < u, v > 回答,如果删去这条边,从 s 到 v 的最短路长度是否会改变。无权的;

一遍bfs求从s点出发的到每个点的单源最短路d[i],对于一条边<u,v>,如果d[v]=d[u]+1,说明是最短路上的边,保留下来;

一个点的入度>=2,就不会改变,否则会改变

拓扑排序

有向无环图的拓扑排序即将所有顶点排为线性序列,使得对于任意的 < u, v >∈ E,都有 u 在线性序列中出现于 v 之前。
有向图中如果有环,则一定不存在拓扑排序;如果没有环,则一定存在拓扑排序。



选取一个入度为 0 的点记为 u

将 u 添加到线性序列末端

删去所有 u 的出边

重复上述步骤直到所有点都被加入序列

例1

有 n 项任务,有 m 个限制,第 i 个限制要求执行任务 ui 之前必须要完成任务 vi。请问是否存在合适的任务执行顺序,满足所有的限制。

将每个任务视为一个点,任务之间的依赖构成了有向边。如果该有向图中没有环,则存在拓扑排序,而拓扑排序就是可行的任务执行顺序;如果该有向图中存在环,则无解。

例2

有 n 项任务,有 m 个限制,限制有如下两种:

? 执行 u 任务之前必须要完成 v 任务

? 存在某一时刻, u 和 v 任务都在执行

请问是否存在安排每个任务起始时间和结束时间的方案,满足所有的限制

对每个线段,用两个点来表示。一个表示其实时间,一个表示结束时间;

对于任务1,也就是对u的开始时间的点向v的结束时间的点连边;

对于任务2,u的开始时间要在v的结束时间之后,v的开始时间也要在u的结束时间之后;

然后对每条线段,还要从这条线段的结束点向开始点连一条边;

例3

对于带边权的有向无环图,求单源最短路。

记起点为 s,拓扑排序形如$ a_1, a_2, . . . , a_t, s, b_1, b_2, . . . , b_k$,记点i 的最短路为 di。

\(d[v]=\min\limits_{<u,v>∈E}\{d[u]+w_{u,v}\}\)

从 s 出发无法走到 \(a_1, a_2, . . . , a_t\),对这些点其最短路为 ∞

从 s 出发走到 bi 之前一定只经过 \(b_1, b_2, . . . , b_{i-1}\),即 dbi 的求解依赖于 \(d_{b_1}, d_{b_2}, . . . , d_{b_{i-1}}\)

按顺序依次求解 ds, db1, db2, . . . , dbk 即可

POJ 1094 Sorting It All Out

An ascending sorted sequence of distinct values is one in which some form of a less-than operator is used to order the elements from smallest to largest. For example, the sorted sequence A, B,C, D implies that A < B, B < C and C < D. in this problem, we will give you a set of relations of the form A < B and ask you to determine whether a sorted order has been specifed or not.
由一些不同元素组成的升序序列是可以用若干个小于号将所有的元素按从小到大的顺序 排列起来的序列。例如,排序后的序列为 A, B, C, D,这意味着 A < B、 B < C 和 C < D。在本题中,给定一组形如 A < B 的关系式,你的任务是判定是否存在一个有序序列。输出到哪一项可以确定顺序或者在这一项最先出现冲突,若所有的小于关系都处理完了都不能确定顺序也没有出现冲突,就输出不能确定。

冲突:拓扑排序排不出来就是冲突的(有环);

拓扑排序时,队列中永远没有出现大于一个元素的时候,就是唯一确定的;

不确定时,即队列中有时有>1个点;

BZOJ 2200 道路和航线

FJ 正在一个新的销售区域对他的牛奶销售方案进行调查。他想把牛奶送到 T 个城镇 (1 ≤ T ≤ 25000),编号为 1 到 T。这些城镇之间通过 R 条道路 (1 ≤ R ≤ 50000) 和 P 条航线(1 ≤ P ≤ 50000) 连接。每条道路 i 或者航线 i 连接城镇 Ai 到Bi,花费为 Ci。对于道路, 0 ≤ Ci ≤ 10000; 然而航线的花费很神奇,花费 Ci 可能是负数 (-10000 ≤ Ci ≤ 10000)。道路是双向的,可以从 Ai 到 Bi,也可以从 Bi 到 Ai,花费都是 Ci。然而航线与之不同,只可以从 Ai 到 Bi。事实上,由于最近恐怖主义太嚣张,为了社会和谐,出台了一些政策保证:如果有一条航线可以从 Ai 到 Bi,那么保证不可能通过一些道路和航线从 Bi 回到Ai。(有向边不存在于任何一个环,环都是正权无向边)由于 FJ 的奶牛世界公认?分给力,他需要运送奶牛到每一个城镇。他想找到从发送中心城镇 S 把奶牛送到每个城镇的最便宜的方案,或者知道这是不可能的。 (求从s出发到某个点的单源最短路);O(nlogn)

把所有无向边加进去,形成若干连通块,看成一个大的点,然后加入有向边,形成一个DAG,如果有连通块的入度为0,直接连通块内跑dijkstar,有向边按拓扑序dp,更新dis,连通块内部使用dijkstar来做;



注意到如果有一条航线可以从 Ai 到 Bi,那么保证不可能通过一些道路和航线从 Bi 回到 Ai。
换言之,不存在包含航线(负权单向边)的环。
首先加入所有正权无向边,找出所有连通块,每个连通块缩为一个点。再加入所有单向边,此时图一定为 DAG。
在 DAG 上用 BFS 更新最短路,在正权无向边组成的连通块(缩点)内部使用 Dijkstra 更新最短路。



最短路

全局最短路 Floyd

单源最短路 Dijkstra SPFA Bellman-Ford

Floyd

基于动态规划, Fk,u,v, 表示使用点 1, 2, . . . , k 时,点 u 到点v 的最短路

从小到大枚举 k, u 和 v 之间的最短路要么不经过 k,要么经过 k 一次且除此之外只包含前 k - 1 个点

\(F_{k,u,v} =min\{F_{k-1,u,v}, F_{k-1,u,k} + F_{k-1,k,v}\}\)

for(int k=1;k<=n;k++)//k要写外面!
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            f[k][i][j]=min(f[k][i][j],f[k-1][i][k]+f[k-1][k][j]);
            f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
        }

易见,使用二维数组不断覆盖更新即可。
时间复杂度 \(O(N^3)\)
空间复杂度 \(O(N^2)\)
可以处理含有负权边的情况,如果含有负环,则存在 i 使得
\(F_{i,i} < 0\)。

传递闭包?

判断两点是否可达:

\(bool \ f[i][j]\)表示i到j是否可达:

for(int k=1;k<=n;k++)
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            f[i][j]|=f[i][k]&f[k][j];

预防毒瘤出题人:

for(int k=1;k<=n;k++)
    for(int i=1;i<=n;i++)if(f[i][k])
        for(int j=1;j<=n;j++)if(f[k][j])
            f[i][j]=true;

Dijkstar

适用于没有负权边的图。

将所有点分为两个集合,最短路确定的集合 S 和最短路未确定的集合 T,初始 S ={s}

求 T 中每个点 v 的当前最短路

\(d_v=\min_{<u,v>∈E,u∈S}\{d_u + w_{u,v}\}\)

取出 T 中 \(d_v\) 最小的点,其最短路一定就是 \(d_v\),将其加入 S

不断重复上面的操作,直到所有点的最短路都确定

朴素写法时间复杂度较劣,可以采用堆优化至$ O((N + M)logN) $

using pii=pair<int,int>

priority_queue<pii,veector<pii>,greater<pii> > q;

void dijkstar(){
    memset(dis,inf,sizeof(dis));
    q.push(make_pair(dis[s]=0,s));
    while(!q.empty()){
        int u=q.top().second;
        int d=q.top().first;
        q.pop();
        if(d!=dis[u]) continue;
        for(int i=head[u],v,w;i;i=edge[i].next){
            if(v=to[i],w=edge[i].dis,dis[v]>d+w)
                q.push(make_pair(dis[v]=d+w,v));
        }
    }
}

Bellman-Ford

初始令 \(d_s\) = 0,其余 \(d_i\) = ∞

依次使用每一条边 < u, v > 更新,$ d_v = min{d_v, d_u + w_{u,v}}$

不断循环直到所有 \(d_i\) 都不会更新

因为任何一条最短路包含至多 n - 1 条边,没有负环则不超过 n 轮就会停止

时间复杂度 O(NM)

空间复杂度 O(N + M)

可以对包含负权边的图使用,如果存在负环,则循环超过 n 轮后依然不会停止,可以用来判断负环是否存在。

SPFA

考虑使用队列优化 Bellman-Ford 算法,如果更新了 \(d_u\),则将 u入队。每次取队首 u 更新其邻点 v 的 \(d_v\)。

最差复杂度O(NM);

原文地址:https://www.cnblogs.com/zhuier-xquan/p/11328917.html

时间: 2024-11-14 11:35:14

乱七八糟的图论1的相关文章

关于图论的若干巴拉巴拉

最近课堂上正在讲图论 先安利MIT课程:http://open.163.com/special/opencourse/algorithms.html 因为本人对图论的概念并不是很清楚,所以还是整理一下吧. 1.图论的基本概念 几种常见的图的分类: 类型 边 允许多重边 允许环 简单图 无向 否 否 多重图 无向 是 否 伪图 无向 是 是 有向图 有向 否 是 有向多重图 有向 是 是 完全图:n个顶点上的完全图是在每对不同顶点之间都恰有一条边的简单图. 二分图:若把简单图G的顶点集合分为两个不

2017清北学堂集训笔记——图论

我们进入一个新的模块——图论! emmmmm这个专题更出来可能有点慢别介意,原因是要划的图和要给代码加的注释比较多,更重要的就是...这几个晚上我在追剧!!我们的少年时代超级超级超级好看,剧情很燃啊!!咳咳,好吧下面回归正题. 一.图的存储: 1.邻接矩阵: 假设有n个节点,建立一个n×n的矩阵,第i号节点能到达第j号节点就将[i][j]标记为1(有权值标记为权值), 样例如下图: 1 /*无向图,无权值*/ 2 int a[MAXN][MAXN];//邻接矩阵 3 int x,y;//两座城市

第九节 图论和搜索

1. 图论算法(用BFS,DFS) 拓扑排序 克隆图 找连通块 六度问题 2.BFS 队列实现:    树中的BFS与图中的BFS有什么不同?树中没有环,图中有环需要一个set来记录搜索过的节点: 应用:图的遍历,最短路径 3 搜索   搜索题的套路比较固定.

图论(A*算法,K短路) :POJ 2449 Remmarguts&#39; Date

Remmarguts' Date Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 25216   Accepted: 6882 Description "Good man never makes girls wait or breaks an appointment!" said the mandarin duck father. Softly touching his little ducks' head, h

ACM 图论入门

①图论基础 图由点和边组成 记顶点集合为V 边集合为E的图为G=(V,E) 图可分为有向图和无向图.如表示朋友关系的图为无向图,表示点之间大小关系的图为有向图. 边也可以带有权值,带有权值称为有权图,不带有权值称为 无权图. 一.关于无向图 任意两点之间都有路径的图叫做连通图,顶点连接的边数称为这个点的度. 没有环的连通图就是树,没有环的非连通图就是森林. 一棵树的边数=顶点数-1.反之 边数=顶点数-1的连通图就是树. 二.关于有向图 以一个点为起点的边数称作这个点的出度,以一个点为终点的边数

Codeforces 444A DZY Loves Physics(图论)

题目链接:Codeforces 444A DZY Loves Physics 题目大意:给出一张图,图中的每个节点,每条边都有一个权值,现在有从中挑出一张子图,要求子图联通,并且被选中的任意两点,如果存在边,则一定要被选中.问说点的权值和/边的权值和最大是多少. 解题思路:是图论中的一个结论,最多两个节点,所以枚举两条边就可以了.我简单的推了一下,2个点的情况肯定比3个点的优. 假设有3个点a,b,c,权值分别为A,B,C 现a-b,b-c边的权值分别为u,v 那么对于两点的情况有A+Bu,B+

图论算法之DFS与BFS

概述(总) DFS是算法中图论部分中最基本的算法之一.对于算法入门者而言,这是一个必须掌握的基本算法.它的算法思想可以运用在很多地方,利用它可以解决很多实际问题,但是深入掌握其原理是我们灵活运用它的关键所在. 含义特点 DFS即深度优先搜索,有点类似广度优先搜索,也是对一个连通图进行遍历的算法.它的思想是从一个顶点V0开始,沿着一条路一直走到底,如果发现不能到达目标解,那就返回到上一个节点,然后从另一条路开始走到底,这种尽量往深处走的概念即是深度优先的概念. 由于用到递归,当节点特别多且深度很大

codevs——1019 集合论与图论

1019 集合论与图论 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 查看运行结果 题目描述 Description 集合论与图论对于小松来说是比数字逻辑轻松,比数据结构难的一门专业必修课.虽然小松在高中的时候已经自学过了离散数学中的图论,组合,群论等知识.但对于集合论,小松还是比较陌生的.集合论的好多东西也涉及到了图论的知识. 在第四讲的学习中,小松学到了“有序对”这么一个概念,即用<x, y>表示有序对x和y.要注意的是有序对<x, y>

cdoj1580 简单图论问题

地址:http://acm.uestc.edu.cn/#/problem/show/1580 题目: 简单图论问题 Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submit Status 给出一个无向图,该图由nn个点和mm条边组成,每个点和每条边都有一个权值.对于该图的任意一个子图,我们定义A是该子图的点权和,B是该子图的边权和,C=A/b=AB是该子图的powerpow