Loading

搜索和图论之DFS、BFS和拓扑排序

1.DFS

时间复杂度\(O(n+m)\)

例题 846. 树的重心 - AcWing题库

题目概述

找出树的重心,重心是一个节点,删除该结点后可以使得剩余连通图中点数的最大最小

解题思路

\((1)\) 每个节点在遍历时return:\(子节点个数+1\)

\((2)\) 每个节点在遍历时可计算更新:\(max(各个子树的节点的最大值,节点总数-(子节点+1))\)

完整代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;  //节点数量
const int M=2*N;  //边的数量
int h[N],e[M],ne[M],idx,re[N],tmax,tsize; 
void add(int a,int b)
{
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
int dfs(int u)
{
	re[u]=1;
	int size=1,curmax=0;
	for(int i=h[u];i!=-1;i=ne[i])
	{
		if(re[e[i]]==0) 
		{
			int sonsize=dfs(e[i]);
			size+=sonsize;
			curmax=max(curmax,sonsize);
		}
	}
	curmax=max(curmax,tsize-size);
	if(curmax<tmax) tmax=curmax;
	return size;
}
int main()
{
	int a,b;
	idx=0;
	memset(h,-1,sizeof(h));
	memset(re,0,sizeof(re));
	cin>>tsize;
	tmax=tsize;
	for(int i=1;i<tsize;i++)
	{
		cin>>a>>b;
		add(a,b);
		add(b,a);
	}
	dfs(1);
	cout<<tmax;
	return 0;
}

2.BFS

时间复杂度\(O(m+n)\)

例题 847. 图中点的层次 - AcWing题库

题目概述

所有边的长度为 \(1\),求 \(1-n\) 的最短路径

解题思路

\(d[j]\) 表示 \(1-j\) 的距离初始化为 \(\infty\)

完整代码

#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int N=1e5+10;  //节点数量
const int M=2*N;  //边的数量
int h[N],d[N],e[M],ne[M],idx=0,re[N]; 
void add(int a,int b)
{
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void bfs(int u)
{
	queue<int> q;
	re[u]=1;
	q.push(u);
	while(!q.empty())
	{
		int t=q.front();
		q.pop();
		for(int i=h[t];i!=-1;i=ne[i])
		{
			int j=e[i];
			if(!re[j])
			{
				re[j]=1;
				d[j]=d[t]+1;
				q.push(j);
			}
		}
	}
	
}
int main()
{
	int n,m,a,b;
	cin>>n>>m;
	memset(h,-1,sizeof h);
	memset(d,INF,sizeof d);
	d[1]=0;
	for(int i=1;i<=m;i++)
	{
		cin>>a>>b;
		add(a,b);
	}
	bfs(1);
	if(d[n]==INF) cout<<-1;
	else cout<<d[n];
	return 0;
}

3.拓扑排序

定义:拓扑序列中所有节点都是从前指向后(针对有向图)

有向无环图一定存在拓扑序列,因而有向无环图也被成为拓扑图

例题 848. 有向图的拓扑序列 - AcWing题库

题目概述

求一有向图的拓扑序列

解题思路

\((1)\) 利用 \(d[j]\) 记录 \(j\) 节点的入度

\((2)\) 数组模拟队列:\(hh=0,tt=0\)

\(q[tt++]=?\) 表示入队 \(q[++hh]=?\) 表示出队

\((3)\) 把入度为 \(0\) 的都入队,弹出队头元素,遍历其所有连接的节点,删除连接的边(即\(d[j]--\)),即只要 \(d[j]==0\) 把其压入队列

\((4)\) return \(tt-n\)

​ 如果存在环,不会进入队列,则 \(tt-n<0\)

完整代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
const int M=2*N;
int h[N],e[M],ne[M],idx,d[N],q[N],n,m;
void add(int a,int b)
{
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
bool topsort()
{
	int hh=0,tt=0;
	for(int i=1;i<=n;i++)
	{
		if(d[i]==0)
			q[tt++]=i;
	}
	while(hh<tt)
	{
		int u=q[hh++];
		for(int i=h[u];i!=-1;i=ne[i])
		{
			int j=e[i];
			d[j]--;
			if(d[j]==0) q[tt++]=j;
		}
	}
	return tt==n;
}
int main()
{
	cin>>n>>m;
	memset(d,0,sizeof d);
	memset(h,-1,sizeof h);
	for(int i=1;i<=m;i++)
	{
		int a,b;
		cin>>a>>b;
		add(a,b);
		d[b]++;
	}
	if(!topsort()) cout<<-1;
	else 
	{
		for(int i=0;i<n;i++)
		{
			cout<<q[i]<<" ";
		}	
	}
	return 0;
}
posted @ 2024-01-20 00:15  cyxcc  阅读(20)  评论(0)    收藏  举报