0
点赞
收藏
分享

微信扫一扫

图论基础(图和最短路)

mafa1993 2022-03-12 阅读 38

树也是一种特殊的图,图上每一个点有出度和入度,对于有向图来说,出度表示顶点的出边,入度表示顶点的入边,图可根据是否有边权分为有权图和无权图,一般来说,对于无权图求最短路时,可以将其赋值为1。可以证明,有向无环图一定存在拓扑序列,因此有向无环图又被成为拓扑图。具体看如下。

建图

邻接矩阵:邻接矩阵通过一个二维数组a[i][j]来存,首先通过memset(a,0x3f,sizeof(a))来给其赋初值为无穷大,每读入一条边就给其赋值为边权值,表示一条边从i指向j,权值为a[i][j],若无向图存两遍即可,时间复杂度和空间复杂度都为O(n^2),不难发现,邻接矩阵存图对时间和空间的消耗都较大,适用于存稠密图,但若是存储稀疏图,会造成大量的空间浪费。故当输入边集较多时,一般不采用邻接矩阵

邻接表:

数组实现

(模板来自于y总,个人感觉这种写法更像链式前向星...?)

// 对于每个点k,开一个单链表,存储k所有可以走到的点。h[k]存储这个单链表的头结点
int h[N], e[N], ne[N], idx;

// 添加一条边a->b
void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}

// 初始化
idx = 0;
memset(h, -1, sizeof h);

vector实现

#include<iostream>
#include<queue>
#include<vector>
using namespace std;

const int N = 1e3;

int n, m;//n为点数,m为边数
vector<pair<int, int>>h[N]; //N为边的起始点,first为边的入点,second为边的权值
struct node {
	int id; int d;//编号和距离
	node(){}
	node(int id,int d):id(id),d(d){}
	//重新建立优先级,实现小根堆
	bool operator<(const node& A) const {
		return d > A.d;
	}
};

int main()
{
	cin >> n >> m;
	while (m--)
	{
		int x, y, z;
		cin >> x >> y >> z;
		h[x].push_back(make_pair(y, z));//有向图的存法
	}
}

需要注意的是,因为求最短路时(如dijkstra)需要用到优先队列,但是优先队列默认大根堆,因此需要在结构体中修改他的优先级,将大根堆改为小根堆,但这并不是邻接表存图的主要内容。

链式前向星:

int head[maxn];//表示以i为起点的最后一个点的编号,初始为-1
int cnt = 1;//cnt表示边的编号
struct node {
	int v, w, next;//next表示与这条边起点相同的上一条边的编号
}edge[maxn];
void addedge(int u, int v, int w)
{
	edge[cnt].v = v;
	edge[cnt].w = w;
	edge[cnt].next = head[u];
	head[u] = cnt++;
}
//初始化
	memset(head, -1, sizeof(head));

/*若要遍历图, i表示点,j首先为以i为起点的最后一个点的编号,j不为 - 1
则证明还有连通的边,j又为与这条边起点相同的上一条边,若遇见-1,则表示
已经没有以i为起点的边了,结束循环,遍历下一个点
*/
for(int i = 0;i < n;i++)
	for(int j = head[i];j != -1;j = edge[j].next)

图的遍历

图的深度优先遍历(基于链式前向星建图):
 

int dfs(int u)
{
    st[u] = true; // st[u] 表示点u已经被遍历过

    for (int i = head[u]; i != -1; i = edge[i].next)
    {
        int j = e[i];
        if (!st[j]) dfs(j);
    }
}

图的宽度优先遍历:

queue<int> q;
st[1] = true; // 表示1号点已经被遍历过
q.push(1);

while (!q.empty())
{
    int t = q.front();
    q.pop();

    for (int i = head[t]; i != -1; i = edge[i].next)
    {
        int j = edge[i].next;
        if (!st[j])
        {
            st[j] = true; // 表示点j已经被遍历过
            q.push(j);
        }
    }
}

最短路是图论里一个重要的问题,给定一个图,求一条从起点到终点的路径,使得边权和最小。

最短路分为单源最短路径(从某个源点到其他各个顶点的最短距离)和多源最短路径(任意两个顶点之间的最短距离)....

现在是一点三十一分,还是先睡觉算了....

举报

相关推荐

0 条评论