搜索与图论
树与图的存储
- 邻接矩阵:g[a][b]存储边a→b
- 邻接表:对于每个点k,开一个单链表,存储k所有可以走到的点。h[k]存储这个单链表的头节点
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
int h[N],e[N],idx,ne[N]; //添加一条边a->b void add(int a,int b){ e[idx]=b,ne[idx]=h[a],h[a]=idx++; } //初始化 idx=0; memset(h,-1,sizeof h);
树与图的遍历
- //时间复杂度 O(n+m), n 表示点数,m 表示边数
- dfs AcWing 846. 树的重心
int dfs(int u){ st[u]=true; for(int i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(!st[j])dfs(j); } }
- bfs AcWing 847. 图中点的层次
int bfs(){ queue<int> q; st[1]=true; q.push(1); while(!q.empty()){ int t=q.front(); q.pop(); for(int i=h[t];i!=-1;i=ne[i]){ int j=e[i]; if(!st[j]){ st[j]=true; q.push(j); } } } }
拓扑排序
- 时间复杂度 O(n+m), n 表示点数,m 表示边数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
bool topsort(){ int hh=0,tt=-1; for(int i=1;i<=n;++i)if(!d[i])q[++tt]=i; while(hh<=tt){ int t=q[hh++]; for(int i=h[t];i!=-1;i=ne[i]){ int j=e[i]; if(--d[j]==0)q[++tt]=i; } } // 如果所有点都入队了,说明存在拓扑序列;否则不存在拓扑序列。 return tt==n-1; }
kruscal算法
- 时间复杂度是 O(mlogm), n 表示点数,m 表示边数
- AcWing 859. Kruskal算法求最小生成树
- 适合边少点多
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> using namespace std; int n,m;// n是点数,m是边数 int p[N];// 并查集的父节点数组 struct Edge{// 存储边 int a,b,w; bool operator<(const Edge &W)const{ return w<W.w; } }edges[M]; int find(int x){//并查集核心操作 if(p[x]!=x){ p[x]=find(p[x]); } return p[x]; } int kruscal(){ sort(edges,edges+m); for(int i=1;i<=n;++i)p[i]=i; int res=0,cnt=0;//cnt记录连通的边数 for(int i=0;i<m;++i){ int a=edges[i].a,b=edges[i].b,w=edges[i].w; a=find(a),b=find(b); if(a!=b){ // 如果两个连通块不连通,则将这两个连通块合并 p[a]=b; res+=w; cnt++; } } if(cnt<n-1)return INF; return res; }
朴素Prim算法
- 时间复杂度是 O(n*n+m), n 表示点数,m 表示边数
- AcWing 858. Prim算法求最小生成树
- 适合点多边少
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; const int N=1e5+5,M=2e5+5,INF=0x3f3f3f3f; int n;// n表示点数 int g[N][N];// 邻接矩阵,存储所有边 int dis[N];// 存储其他点到当前最小生成树的距离 bool st[N];// 存储每个点是否已经在生成树中 // 如果图不连通,则返回INF(值是0x3f3f3f3f), 否则返回最小生成树的树边权重之和 int prim(){ memset(dis,0x3f,sizeof dis); int res=0; for(int i=0;i<n;++i){ int t=-1; for(int j=1;j<=n;++j){ if(t==-1||dis[j]<dis[t])t=j; } if(i&&dis[t]==INF)return INF; if(i)res+=dis[t]; st[t]=true; for(int j=1;j<=n;++j)dis[j]=min(dis[j],g[t][j]); } return res; }