图的存储
邻接矩阵
一般只适用于顶点数目不太大的题目(一般不超过1000)
邻接表
顶点数大于1000的题目
- vector实现
开一个vector数组Adj[N],其中N为顶点个数
- 如果邻接表只存储每条边的终点编号,而不存储边权,则vector中的元素类型可以直接定义为int
- 如果需要存储边权,则把替换类型替换为结构体Node
strcut Node{
int v, w;
Node(int _v, int _w) : v(-v), w(_w) {}
}
//此时可以不定义临时变量即可实现加边操作
Adj[i].push_back(Node(3, 4));
图的遍历
DFS
- 伪代码
DFS(u) { //访问顶点u
vis[u] = true; //设置u已被访问
for(从u出发能到达的所有顶点v) //枚举
if(vis[v] = false)
DFS(v);
}
DFSTrave(G) {
for(G的所有顶点u) //枚举
if (vis[u] == false
DFS(u); //访问u所在的连通块
}
- 邻接矩阵 版本
int n, G[maxn][maxn]; //n为顶点数,maxn为最大顶点数
bool vis[maxn] = {false};
void DFS(int u, int depth) {
vis[u] = true; //设置u已被访问
//如果需要对u进行一些操作,在此处进行
for(int v = 0; v < n; v++) //枚举所有结点
if(vis[v] == false && G[u][v] != INF) //若未曾访问,且u可到达v
DFS(v, depth + 1); //访问i,深度+1
}
void DFSTrave() { //遍历图G
for(int u = 0; u < n; u++)
if(vis[u] == false)
DFS(u, 1); //初始为第一层
}
- 邻接表 版本
vector<int> Adj[maxn]; //图G的邻接表
int n; //n为顶点数
bool vis[maxn] = {false};
void DFS(int u, int depth) {
vis[u] = true; //设置u已被访问
//如果需要对u进行一些操作,在此处进行
for(int i = 0; i < Adj[u].size(); i++) { //枚举所有结点
int v = Adj[u][i]; //vector可按下标访问
if(vis[v] == false) //若未曾访问,且u可到达v
DFS(v, depth + 1); //访问i,深度+1
}//for
}
void DFSTrave() { //遍历图G
for(int u = 0; u < n; u++)
if(vis[u] == false)
DFS(u, 1); //初始为第一层
}
BFS
- 伪代码
BFS(u) { //遍历u所在的连通块
queue q; //定义队列
将u入队列
inq[u] = true; //设置u已入队列
while(q非空) {
取出q的队首元素u进行访问;
for(从u出发能到达的所有顶点v)
if(inq[v] == false){ //若未曾加入队列
将v入队列
inq[v] = true; //标记v加入队列
}
}//while
}
BFSTrave() { //遍历图
for(G的所有顶点u)
if(inq[u] == false)
BFS(u); //遍历u所在的连通块
}
- 邻接矩阵 版本
int n, G[maxn][maxn]; //n为顶点数
bool inq[maxn] = {false}; //标记结点是否入队列
void BFS(int u) {
queue<int> q;
q.push(u);
inq[u] = true; //标记已入队列
while(!q.empty()) {
int u = q.front();
q.pop();
for (int v = 0; v < n; v++) {
if(inq[v] == false && G[u][v] != INF) {//未曾入队列,且可达
q.push(v);
inq[v] = true; //标记v已经入队列
}
}
}//while
}
void BFSTrave() { //遍历图
for(int u = 0; u < n; u++)
if(inq[u] == false)
BFS(u); //遍历u所在的连通块
}
- 邻接表 版本
vector<int> Adj[maxn]; //图G的邻接表
int n; //n为顶点数
bool inq[maxn] = {false};
void BFS(int u) {
queue<int> q;
q.push(u);
inq[u] = true; //标记已入队列
while(!q.empty()) {
int u = q.front();
q.pop();
for (int i = 0; i < Adj[u].size(); i++) {
int v = Adj[u][i]; //vector可按下标访问
if(inq[v] == false) {//未曾入队列
q.push(v);
inq[v] = true; //标记v已经入队列
}
}
}//while
}
void BFSTrave() { //遍历图
for(int u = 0; u < n; u++)
if(inq[u] == false)
BFS(u); //遍历u所在的连通块
}
注:**当题目要求输出**结点的层号时,只需把vector<>中存储的元素换成结构体即可,结构体中包括结点编号和层号信息。遍历的同时更新层号信息,子节点是父节点结点的层号+1。结构体如下:
struct node {
int v;
int layer;
};
应用练习
Battle Over Cities(A1013)并查集和DFS两种实现