数构作业:图总结

数构作业:图总结

一.思维导图

YRNx2T.png

二.重要概念的笔记

1)图的表示
1.邻接矩阵

普通图:二维数组S[N][N] a[i][j]

特殊的无向图:一维数组S[(N(N+1)/2] a[i*(i+1)/2+j]

缺点:对稀疏图,浪费空间和时间,适合满图

2.邻接表

邻接表(一定要足够稀疏,才会省空间)

G[N],每一行都是一个指针,指针指向一串链表,对应稀疏矩阵中的非0元素。

需要N个头指针 + 2E个结点(每个结点至少2个域),则E小于多少是省空间的?

N +2*2E<N*N

用邻接表表示有N个顶点、E条边的图,则遍历图中所有边的时间复杂度为:

O(N+E)

2)图的遍历
1.DFS

伪代码如下:

void DFS ( Vertex V ){
	visited[V] = true;
	for( V的每个邻接点W ){
		if( !visited[W] )
			DFS(W);
	}
}

时间复杂度:

1)邻接矩阵存储 O(N^2)

2)邻接表存储 O(N+E)

优缺点:优点是内存消耗小;缺点是难以寻找最优解

2.BFS

伪代码如下:

void BFS ( Vertex V ){
	visited[V] = true;
	Enqueue(V,Q);
	while(!IsEmpty(Q)){
		V = Dequeue(Q);
		for ( V的每个邻接点W ){
		if ( !visited[W] ){
			visited[W] = true;
			Enqueue(W, Q);
		}
	}
}

时间复杂度同DFS:

1)邻接矩阵存储 O(N^2)

2)邻接表存储 O(N+E)

优缺点:优点是可以得到最优解;缺点是在树的层次较深并且子节点个数较多的情况下,消耗内存现象十分严重,因此,BFS适用于节点的子节点个数不多,并且树的层次不太深的情况

3)最小生成树之普里姆算法
void MiniSpanTree_P (MGraph G, VertexType u) { 
	//用普里姆算法从顶点u出发构造网G的最小生成树 
	k = LocateVex ( G, u );
    for (j=0; j<G.vexnum; ++j )//辅助数组初始化
    if (j!=k)
    closedge[j] = {u,G.arcs[k][j].adj };
    closedge[k].lowcost = 0;//初始,U={u}
    for (i=0; i<G.vexnum; ++i) {
    	继续向生成树上添加顶点;
    }
	k = Min(closedge);//求出加入生成树的下一个顶点k
    printf(closedge[k].adjvex, G.vexs[k]); //输出生成树上一条边
    closedge[k].lowcost = 0;//第k顶点并入U集 
    for(j = 0; j < G.vexnum; ++j) //修改其它顶点的最小边
    if (G.arcs[k][j].adj < closedge[j].lowcost)
    closedge[j]={G.vexs[k], G.arcs[k][j].adj
 }

三.疑难问题及解决方案

Dijkstra算法还有path数组

与求最短路相比,增加一个path数组,来记录最短路的路径

先将path[i]=-1,之后每次找出最短路的点p后将path[j]=p

用path[j]=i表示从i到j最短路的路径

for(int j=1; j<=n; j++){
    if(!visited[j] && dis[p]+mapp[p][j]<dis[j]){
        dis[j]=dis[p]+mapp[p][j];
        path[j]=p;
    }
}

算法代码

#include <bits/stdc++.h>
 
using namespace std;
typedef long long ll;
const int maxx = 999999999;
const int INF = 1e3 + 100;
int n, m;
int mapp[INF][INF];
int dis[INF];
int path[INF];
bool visited[INF];
void Dijkstra(int v0) {
    for (int i = 1; i <= n; i++) {
        dis[i] = mapp[v0][i];
        visited[i] = 0;
        path[i] = -1;
    }
    visited[v0] = 1;
    for (int i = 1; i <= n; i++) {
        int p, minn = maxx;
        for (int j = 1; j <= n; j++) {
            if (!visited[j] && dis[j] < minn) {
                p = j;
                minn = dis[j];
            }
        }
        visited[p] = 1;
        for (int j = 1; j <= n; j++) {
            if (!visited[j] && dis[p] + mapp[p][j] < dis[j]) {
                dis[j] = dis[p] + mapp[p][j];
                path[j] = p;
            }
        }
    }
    return;
}
int main() {
    while (cin >> n >> m) {
        if (n == 0 && m == 0) break;
        for (int i = 0; i <= n; i++) {
            for (int j = 0; j <= n; j++) {
                mapp[i][j] = maxx;
            }
        }
        int s, t, d;
        while (m--) {
            cin >> s >> t >> d;
            mapp[s][t] = d;
        }
        Dijkstra(1);
        for (int i = 2; i <= n; i++) {
            if (i == 2) cout << dis[i];
            else cout << " " << dis[i];
        }
        cout << endl;
        for (int i = 2; i <= n; i++) {
            cout << i;
            int p = i;
            while (path[p] != -1) {
                cout << "-->" << path[p];
                p = path[p];
            }
            cout << "-->" << "1" << endl;
        }
    }
    return 0;
}
posted @ 2020-05-17 21:51  Sogger  阅读(375)  评论(0编辑  收藏  举报