-
图的基本概念
(1) 有向图、无向图
(2) 度数(出度、入度)
(3) 简单图:不存在顶点到其自身的边,且同一条边不重复出现
(4) 路径、环、简单路径
(5) 无向完全图:任意两个顶点之间都存在边,有n个顶点的无向完全图有 n × (n - 1) / 2条边
(6) 有向完全图:任意两个顶点之间都存在方向护卫相反的两条弧,有n个顶点的无向完全图有 n × (n - 1) 条弧
(7) 稀疏图&稠密图:有很少条边或弧的图称为稀疏图,反之称为稠密图,相对的概念。 -
图的存储及基本操作
(1) 邻接矩阵:适用于稠密图,可存有向图、无向图。常用。空间复杂度:O(n^2)。无法存重边。
(2) 邻接表:适用于稀疏图,可存有向图、无向图。常用。空间复杂度:O(n + m)。可存重边无法存重边。
(3) 邻接多重表,适用于稀疏图,可存无向图。不常用。空间复杂度:O(n + m)
(4) 十字链表,适用于稀疏图,可存有向图、无向图。不常用。空间复杂度:O(n + m)。
(5) 三元组表,适用于稀疏图,可存有向图,无向图。常用于Bellman-Ford算法、Kruskal算法。空间复杂度:O(m)。可存重边。 -
图的遍历
(1) 深度优先搜索。邻接表存储的时间复杂度:O(n + m)。邻接矩阵存储的时间复杂度:O(n^2)
(2) 广度优先搜索。邻接表存储的时间复杂度:O(n + m)。邻接矩阵存储的时间复杂度:O(n^2) -
拓扑排序
存在拓扑排序等价于不存在环
题目描述
给定一个 n n n 个点 m m m 条边的有向图,点的编号是 1 1 1 到 n n n,图中可能存在重边和自环。
请输出任意一个该有向图的拓扑序列,如果拓扑序列不存在,则输出 − 1 -1 −1。
若一个由图中所有点构成的序列 A A A 满足:对于图中的每条边 ( x , y ) (x, y) (x,y), x x x 在 A A A 中都出现在 y y y 之前,则称 A A A 是该图的一个拓扑序列。
输入格式
第一行包含两个整数 n n n 和 m m m。
接下来 m m m 行,每行包含两个整数 x x x 和 y y y,表示存在一条从点 x x x 到点 y y y 的有向边 ( x , y ) (x, y) (x,y)。
输出格式
共一行,如果存在拓扑序列,则输出任意一个合法的拓扑序列即可。
否则输出 − 1 -1 −1。
数据范围
1 < = n , m < = 1 0 5 1 <= n,m <= 10^5 1<=n,m<=105
输入样例:
3 3
1 2
2 3
1 3
输出样例:
1 2 3
C++ 代码
bfs的写法
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 100010, M = 100010;
int n, m;
bool st[N];
int d[N], q[N];
struct Node{
int id;
Node* next;
Node(int _id): id(_id), next(NULL){}
}*head[N];
void add(int a, int b){
auto p = new Node(b);
p->next = head[a];
head[a] = p;
}
bool topsort(){
int hh = 0, tt = - 1;
for(int i = 1; i <= n; i++)
if(!d[i])
q[ ++ tt] = i;
while(hh <= tt){
int t = q[hh ++];
for(auto p = head[t]; p; p = p->next)
if(-- d[p->id] == 0)
q[++ tt] = p->id;
}
return tt == n - 1;
}
int main(){
scanf("%d%d", &n, &m);
while(m --){
int a, b;
scanf("%d%d", &a, &b);
d[b] ++;
add(a, b);
}
if(!topsort()) puts("-1");
else{
for(int i = 0 ; i < n; i++)
printf("%d ", q[i]);
}
return 0;
}
dfs写法
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 100010, M = 100010;
int n, m;
int st[N];
int q[N], top;
struct Node{
int id;
Node* next;
Node(int _id): id(_id), next(NULL){}
}*head[N];
void add(int a, int b){
auto p = new Node(b);
p->next = head[a];
head[a] = p;
}
bool dfs(int u){
//0表示未搜索,1表示搜索中,2表示已经搜索完毕
st[u] = 1;
for(auto p = head[u]; p; p = p->next){
int j = p->id;
if(!st[j]){
if(!dfs(j)) return false;
}
else if(st[j] == 1) return false;
}
q[top ++] = u;
st[u] = 2;
return true;
}
bool topsort(){
for(int i = 1; i <= n; i++)
if(!st[i] && !dfs(i))
return false;
return true;
}
int main(){
scanf("%d%d", &n, &m);
while(m --){
int a, b;
scanf("%d%d", &a, &b);
add(a, b);
}
if(!topsort()) puts("-1");
else{
for(int i = n - 1; i >= 0; i--)
printf("%d ", q[i]);
}
return 0;
}