1.DFS
时间复杂度 O ( n + m ) O(n+m) O(n+m)
例题 846. 树的重心 - AcWing题库
题目概述
找出树的重心,重心是一个节点,删除该结点后可以使得剩余连通图中点数的最大最小
解题思路
( 1 ) (1) (1) 每个节点在遍历时return: 子节点个数 + 1 子节点个数+1 子节点个数+1
( 2 ) (2) (2) 每个节点在遍历时可计算更新: m a x ( 各个子树的节点的最大值 , 节点总数 − ( 子节点 + 1 ) ) max(各个子树的节点的最大值,节点总数-(子节点+1)) 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 ) O(m+n) O(m+n)
例题 847. 图中点的层次 - AcWing题库
题目概述
所有边的长度为 1 1 1,求 1 − n 1-n 1−n 的最短路径
解题思路
d [ j ] d[j] d[j] 表示 1 − j 1-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 ) (1) (1) 利用 d [ j ] d[j] d[j] 记录 j j j 节点的入度
( 2 ) (2) (2) 数组模拟队列: h h = 0 , t t = 0 hh=0,tt=0 hh=0,tt=0
q [ t t + + ] = ? q[tt++]=? q[tt++]=? 表示入队 q [ + + h h ] = ? q[++hh]=? q[++hh]=? 表示出队
( 3 ) (3) (3) 把入度为 0 0 0 的都入队,弹出队头元素,遍历其所有连接的节点,删除连接的边(即 d [ j ] − − d[j]-- d[j]−−),即只要 d [ j ] = = 0 d[j]==0 d[j]==0 把其压入队列
( 4 ) (4) (4) return t t − n tt-n tt−n
如果存在环,不会进入队列,则 t t − n < 0 tt-n<0 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;
}