a.有向图,无向图,加权有向图,加权无向图
b.连接两个顶点u,v的边记作e=(u,v)
c.不存在环的有向图称为DAG
2.图的邻接矩阵:
a.优点:可以通过M[u][v]直接引用边(u,v),因此只需要常数时间(O(1))即可确定顶点u和顶点v的关系;只要更改M[u][v]只就能完成边的添加与删除,简单且高效
b.缺点:消耗的内存空间等于顶点数的平方。如果图的边数较少,就会浪费较大量的内存;在同一个邻接矩阵中,只能记录顶点u到顶点v的一个关系
c.代码:
// // Created by 叶子 on 2018/2/5. // 邻接矩阵的表示 // #include "iostream" using namespace std; static const int N = 100; int main(){ int M[N][N]; int n,u,k,v; cin >> n; for ( int i = 0 ; i < n ; i ++){ for ( int j = 0 ; j < n ; j ++ ) M[i][j] = 0 ; } for ( int i = 0 ; i < n ; i ++){ cin >> u >> k; u --; for ( int j = 0 ; j < k ; j ++){ cin >> v; v --; M[u][v] = 1; } } for ( int i = 0 ; i < n ; i ++){ for ( int j = 0 ; j < n ; j ++){ if ( j ) cout << " "; cout << M[i][j]; } cout << endl; } }
3.图的深度优先搜索:
a.定义:在图的搜索算法中,深度优先搜索采取的思路是尽可能地访问相邻顶点。设仍存在未搜索邻接边的顶点中最后一个被发现的顶点为v,那么深度优先搜索就是对此顶点的的邻接递归地进行搜索。当v的边全部搜索完毕后,程序沿发现v时所经过的边回溯,继续搜索前一顶点。搜索一直持续到发现当前起点可到达的所有顶点为止。如果仍有顶点未被发现,则选择其中编号最小的一个作为新起来继续探索。
深度优先搜索中需要记录:
d[v]:记录第一次访问v的时刻
f[v]:记录调查完v的邻接表的时刻
b.过程:
1)将最初访问的顶点压入栈
2)如果栈中仍有顶点,则循环进行下述操作:先访问栈顶部的顶点u,然后从当前的顶点u移动至顶点v时,将v入栈。如果当前顶点u不存在未访问的顶点,则将u从栈中删除
c.代码:
#include "iostream" #include "stack" using namespace std; static const int N = 100; static const int WHITE = 0; static const int GRAY = 1; static const int BLACK = 2; int n,M[N][N]; int color[N],d[N],f[N],tt; int nt[N]; int next(int u){ for ( int v = nt[u]; v < n ; v++){ nt[u] = v + 1; if ( M[u][v] ) return v; } return -1; } void dfs_visit(int r){ for ( int i = 0 ; i < n ; i ++) nt[i] = 0 ; stack<int> S; S.push(r); color[r] = GRAY; d[r] = ++tt; while( !S.empty() ){ int u = S.top(); int v = next(u); if ( v != -1){ if ( color[v] == WHITE) { color[v] = GRAY; d[v] = ++tt; S.push(v); } } else { S.pop(); color[u] = BLACK; f[u] = ++tt; } } } void dfs(){ for ( int i = 0 ; i < n ; i ++){ color[i] = WHITE; nt[i] = 0; } tt = 0 ; for ( int u = 0 ; u < n ; u ++){ if ( color[u] == WHITE ) dfs_visit(u); } for ( int i = 0 ; i < n ; i ++){ cout << i + 1 << " " << d[i] << " " << f[i] << endl; } } int main(){ int u,k,v; cin >> n; for ( int i = 0 ; i < n ; i ++){ for ( int j = 0 ; j < n ; j ++) M[i][j] = 0; } for ( int i = 0 ; i < n ; i ++){ cin >> u >> k; u--; for ( int j = 0 ; j < k ; j ++){ cin >> v; v --; M[u][v] = 1; } } dfs(); return 0; }
4.图的广度优先搜索:
a.定义:在广度优先搜索中,要想发现与起点s距离为k+1的顶点,首先要发现所有距离为k的顶点,因此可以求出起点到各顶点的最短矩离
b.要点:使用邻接矩阵实现的广度优先搜索中,由于要调查每个顶点是否与其他点相邻,所以不适用于规模较大的图
c.代码:
// // Created by 叶子 on 2018/2/5. // 广度优先搜索 // #include "iostream" #include "queue" using namespace std; static const int N = 100; static const int INFTY = ( 1 << 2); int n,M[N][N]; int d[N]; void bfs(int s ){ queue<int> q; q.push(s); for ( int i = 0 ; i < n ; i ++) d[i] = INFTY; d[s] = 0 ; int u ; while ( !q.empty()){ u = q.front(); q.pop(); for ( int v = 0 ; v < n ; v ++){ if ( M[u][v] == 0 ) continue; if ( d[v] != INFTY ) continue; d[v] = d[u] + 1; q.push(v); } } for ( int i = 0 ; i < n ; i ++){ cout << i +1 << " " << ( d[i] == INFTY ? ( -1) : d[i] ) << endl; } } int main(){ int u,k,v; cin >> n; for ( int i = 0 ; i < n ; i ++){ for ( int j = 0 ; j < n ; j ++) M[i][j] = 0; } for ( int i = 0 ; i < n ; i ++){ cin >> u >> k; u --; for ( int j = 0 ; j < k ; j ++){ cin >> v; v--; M[u][v] = 1; } } bfs(0); return 0; }
5.连通分量:
a.题目:输入SNS的朋友关系,判断从指定人物出发能否通过双向朋友链抵达指定人物
b.要点:使用邻接且来表示图,其优点是只需与边数成正比的内存空间,其缺点难以有效的删除边
c.代码:
// // Created by 叶子 on 2018/2/5. // 连通分量 // #include "iostream" #include "vector" #include "stack" using namespace std; static const int MAX = 100000; static const int NIL = -1; int n ; vector<int> G[MAX]; int color[MAX]; void dfs(int r,int c){ stack<int> S; S.push(r); color[r] = c; while ( !S.empty()){ int u = S.top(); S.pop(); for ( int i = 0 ; i < G[u].size() ; i ++){ int v = G[u][i]; if ( color[v] == NIL){ color[v] = c; S.push(v); } } } } void assignColor(){ int id = 1; for ( int i = 0 ; i < n ; i ++) color[i] = NIL; for ( int u = 0 ; u < n ; u ++){ if ( color[u] == NIL) dfs(u,id++); } } int main(){ int s,t,m,q; cin >> n >> m; for ( int i = 0 ; i < m ; i ++){ cin >> s >> t; G[s].push_back(t); G[t].push_back(s); } assignColor(); cin >> q; for ( int i = 0 ; i < q ; i ++){ cin >> s >> t; if ( color[s] == color[t] ){ cout << "yes" << endl; }else{ cout << "no" << endl; } } return 0; }