图:

PAT (Advanced Level) Practice 用到图的存储方式,但没有用到图的算法的题目

1122 Hamiltonian Cycle (25)

1126 Eulerian Path (25)

1134 Vertex Cover (25)

1142 Maximal Clique (25)

1154 Vertex Coloring (25)

图的遍历:

1.定义:

  • 顶点的度:与该顶点相连的边的条数
  • 顶点和边量化的属性分别为点权和边权

2.存储

邻接矩阵:

  • 对称的矩阵
  • 若题目中不存在权值,G[i][j]=1表示顶点i和顶点j之间有边,G[i][j]=0表示顶点i和顶点j之间不存在边
  • 如果存在权值,G[i][j]存放边权,不存在的边可以设边权为0、-1或是一个很大的数(INF=0x3f3f3f3f)
  • 邻接矩阵只适用于顶点数目不太大(一般不超过1000)的题目

邻接表:

  • 若只存放每条边的终点编号,vector 元素类型定义为 int 即可
vector<int> Adj[N];
Adj[u].push_back(v);
  • 若同时存放终点编号和边权,可建立结构体,vector 元素类型定义为结构体
struct Node{
   
    int v;
    int weight;
};
vector<Node> Adj[N];
Adj[u].push_back({
   v,weight});

DFS遍历图:

DFS的伪代码:
//注意:如果已知给定的图是一个连通图,则只需要一次DFS就能完成遍历

DFS(u) {
    //访问顶点u
	vis[u]=true;//设置u已被访问
	for(从u出发能到达的所有顶点v)//枚举从u出发可以到达的所有顶点v
		if vis[v]==false //如果v未被访问 
			DFS(v);//递归访问v 
}
DFSTrave(G) {
    //遍历图G 
	for(G的所有顶点u) //对G的所有顶点u
		if vis[u]==false //如果u未被访问
			DFS(u); //访问u所在的连通块 
	
}

定义:

定义maxn为最大顶点数,INF为无穷大
const int maxn=1000;//最大顶点数
const int INF=0x3f3f3f3f;//无穷大

DFS遍历邻接矩阵:

邻接矩阵
int n,G[maxn][maxn];
bool vis[maxn]= {
   false};

void DFS(int u,int depth) {
    //u为当前访问的顶点标号,depth为深度
	vis[u]=true;//设置u已被访问
	//如果需要对u进行一些操作,在这里进行
	//对所有从u出发的分支顶点进行枚举
	for(int v=0; v<n; v++) {
    //对每个顶点v
		if(vis[v]==false&&G[u][v]!=INF) {
    //如果v未被访问,且u可到达v
			DFS(v,depth+1);//访问v,深度加1
		}
	}
}

void DFSTrave() {
    //遍历图G
	for(int u=0; u<n; u++) {
    //对每个顶点u
		if(vis[u]==false) {
   //如果u未被访问
			DFS(u,1); //访问u和u所在的连通块,1表示初始为第一层
		}
	}

}

DFS遍历邻接表:

邻接表
vector<int> Adj[maxn];
int n;
bool vis[maxn]={
   false};

void DFS(int u,int depth){
   
	vis[u]=true;
	for(int i=0;i<Adj[u].size();i++){
   
		int v=Adj[u][i];
		if(vis[v]==false){
   
			DFS(v,depth+1);
		}
	}
}

void DFSTrave(){
   
	for(int u=0;u<n;u++){
   
		if(vis[u]==false){
   
			DFS(u,1);
		}
	}
} 

BFS遍历图:

BFS的伪代码:
BFS(u){
   
	queue q;
	将u入队;
	inq[u]=true;
	while(!q.empty()){
   
		取出q的队首元素u进行访问;
		for(从u出发可达的所有顶点v)
			if(inq[v]=false){
   
				将v入队;
				inq[v]=true; 
			} 
	} 
}
BFSTrave(G){
   
	for(G的所有顶点u)
		if(inq[u]==false){
   
			BFS(u);
	}
}

BFS遍历邻接矩阵:

邻接矩阵
int n,G[maxn][maxn];
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;
			}
		}
	}
}
void BFSTrave(){
   
	for(int u=0;u<n;u++){
   
		if(inq[u]==false){
   
			BFS(u);
		}
	}
} 

BFS遍历邻接表:

邻接表
vector<int> Adj[MAXN];
int 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];
            if (!inq[v]){
   
                q.push(v);
                inq[v] = true;
            }
        }
    }
}
void BFSTrave(){
   
    for (int u = 0; u < n; u++)
        if (!inq[u])
            BFS(u);
}

输出结点层号(邻接表):

  • 与树的BFS遍历一样,可能需要输出连通块内所有其他顶点的层号
  • 定义结构体来存放顶点层号
  • 修改邻接表中的元素为Node(int->Node)
  • 当前层号为L,它所有出边的终点的层号都为L+1
struct Node{
   
    int v;
    int level;
};
vector<Node> Adj[N];
void BFS(int s){
   
    queue<Node> q;
    Node start = {
   s,0};
    q.push(start);
    inq[start.v] = true;
    while(!q.empty()){
   
        Node now = q.front();
        q.pop();
        int u = now.v;
        for (int i = 0; i < Adj[u].size(); i++){
   
            Node next  = Adj[u][i];
            next.level = now.level + 1;
            if (!inq[next.v]){
   
                q.push(next);
                inq[next.v] = true;
            }
        }
    }
}

题目链接:

1021 Deepest Root (25)

1076 Forwards on Weibo (30)