#include<iostream>#include<cstring>usingnamespace std;constint N =1e5+10;int s[N];// 并查集数组,其中 s[x] < 0 表示 x 是根节点,其绝对值表示集合的大小voidinit(){memset(s,-1,sizeof(s));// 初始化并查集数组,全部置为 -1}// 查找 x 所在的集合的根节点/*
int find(int x) {
if (s[x] < 0) return x;
return s[x] = find(s[x]);
}
*/intfind(int x){int rt = x;while(s[rt]>=0){
rt = s[rt];}while(x != rt){int t = s[x];
s[x]= rt;
x = t;}return rt;}// 将 x 和 y 所在的集合合并boolunite(int x,int y){
x =find(x);
y =find(y);if(x == y)returnfalse;// x 和 y 已经在同一集合中,无需合并if(s[x]< s[y]){
s[x]+= s[y];// 将 y 集合并入 x 集合
s[y]= x;}else{
s[y]+= s[x];// 将 x 集合并入 y 集合
s[x]= y;}returntrue;// 合并成功}// luogu P3367intmain(){int n, m;
cin >> n >> m;init();int x, y, z;for(int i =0; i < m; i++){
cin >> z >> x >> y;
cout <<find(x)<<' '<<find(y)<< endl;if(z ==2){if(find(x)==find(y)){
cout <<'Y'<< endl;}else{
cout <<'N'<< endl;}}else{unite(x, y);}}return0;}
bfs
#include<iostream>#include<queue>#include<vector>usingnamespace std;constint MAXN =10010;
vector<int> G[MAXN];// 邻接表存储图bool vis[MAXN];// 记录节点是否已经访问过voidbfs(int start){
queue<int> q;// 队列存储待访问的节点
q.push(start);// 入队起始节点
vis[start]=true;// 标记起始节点已访问while(!q.empty()){int cur = q.front();// 取出队首节点
q.pop();// 对当前节点cur进行操作
cout << cur <<" ";// 将cur的邻接节点入队for(int i =0; i < G[cur].size(); i++){int v = G[cur][i];if(!vis[v]){
q.push(v);
vis[v]=true;}}}}intmain(){int n, m;
cin >> n >> m;// 输入节点数和边数for(int i =0; i < m; i++){int u, v;
cin >> u >> v;// 输入一条边
G[u].push_back(v);
G[v].push_back(u);// 无向图需要加入反向边}bfs(1);// 从1号节点开始BFS遍历return0;}
dfs
#include<iostream>#include<unordered_set>#include<vector>usingnamespace std;constint MAXN =10010;// 定义邻接表存储图的结构
vector<int> G[MAXN];// 定义用于记录是否已经访问过节点的unordered_set
unordered_set<int> vis;// 深度优先遍历函数,从节点u开始遍历voiddfs(int u){// 标记节点u已经被访问过
vis.insert(u);// 输出节点u的编号
cout << u <<' ';// 遍历节点u的邻接节点for(auto v : G[u]){// 如果邻接节点v还没有被访问过,就从v开始继续遍历if(!vis.count(v)){dfs(v);}}}intmain(){int n, m;
cin >> n >> m;// 输入节点数和边数for(int i =0; i < m; i++){int u, v;
cin >> u >> v;// 输入一条边
G[u].push_back(v);
G[v].push_back(u);// 无向图需要加入反向边}dfs(1);// 从1号节点开始BFS遍历return0;}
prim
#include<iostream>#include<vector>#include<queue>#include<cstring>usingnamespace std;constint MAXN =1e5+5;structEdge{int v, w;// 边的终点和权值Edge(int _v,int _w):v(_v),w(_w){}booloperator<(const Edge& e)const{// 重载运算符以实现小根堆return w > e.w;}};
vector<Edge> G[MAXN];// 邻接表存储图bool vis[MAXN];// 标记是否在最小生成树中int dist[MAXN];// 记录点到最小生成树的距离intprim(int s){memset(dist,0x3f,sizeof(dist));// 初始化所有点到最小生成树距离为无穷大
priority_queue<Edge> q;// 定义一个小根堆
q.push(Edge(s,0));// 将起点加入小根堆
dist[s]=0;int res =0;// 最小生成树的总权值while(!q.empty()){int u = q.top().v;// 取出小根堆中距离最小的点
q.pop();if(vis[u])continue;// 如果该点已经在最小生成树中,则跳过
vis[u]=true;
res += dist[u];// 将该点加入最小生成树for(auto e : G[u]){// 遍历与该点相邻的边int v = e.v, w = e.w;if(!vis[v]&& dist[v]> w){// 如果该点未在最小生成树中且距离比当前最短路径更短,则更新距离并加入小根堆
dist[v]= w;
q.push(Edge(v, w));}}}return res;}// Luogu P3366intmain(){int n, m;
cin >> n >> m;int x, y, z;for(int i =0; i < m; i++){
cin >> x >> y >> z;
G[x].push_back({ y, z });
G[y].push_back({ x, z });}int ans =prim(1);for(int i =1; i <= n; i++){if(!vis[i]){
cout <<"orz"<< endl;return0;}}
cout << ans << endl;}
kruskal
#include<iostream>#include<algorithm>#include<vector>usingnamespace std;constint MAXN =1e5+5;structEdge{int u, v, w;Edge(int _u,int _v,int _w):u(_u),v(_v),w(_w){}booloperator<(const Edge& e)const{return w < e.w;}};int n, m;int fa[MAXN];// 初始化并查集voidinit(){for(int i =1; i <= n; i++){
fa[i]= i;}}// 并查集查找根节点intfind(int x){if(fa[x]!= x){
fa[x]=find(fa[x]);}return fa[x];}// Kruskal 算法求最小生成树,返回最小生成树的边权之和intkruskal(vector<Edge>& edges){init();int res =0, cnt =0;sort(edges.begin(), edges.end());// 将所有边按边权从小到大排序for(auto& e : edges){int u = e.u, v = e.v, w = e.w;int x =find(u), y =find(v);if(x == y)continue;// 如果 u 和 v 已在同一集合中,则跳过该边
fa[x]= y;// 否则将 u 所在集合合并到 v 所在集合中
res += w;// 计算最小生成树边权之和
cnt++;// 统计最小生成树的边数if(cnt == n -1)break;// 如果边数达到 n-1,则生成树已经构建完成}return res;}// Luogu P3366intmain(){
cin >> n >> m;
vector<Edge> edges;// 存储所有边for(int i =0; i < m; i++){int u, v, w;
cin >> u >> v >> w;
edges.push_back(Edge(u, v, w));// 将边加入 vector 中}int res =kruskal(edges);// 求最小生成树for(int i =1; i <= n; i++){if(find(i)!=find(1)){
cout <<"orz"<< endl;return0;}}
cout << res << endl;return0;}
dijkstra
#include<iostream>#include<vector>#include<queue>#include<cstring>usingnamespace std;constint MAXN =1e5+5;// 最大点数constint INF =0x3f3f3f3f;// 无穷大structEdge{int v, w;Edge(int _v,int _w):v(_v),w(_w){}};
vector<Edge> G[MAXN];// 邻接表存储图bool vis[MAXN];// 标记是否已确定最短路int dist[MAXN];// 记录起点到各点的最短路voiddijkstra(int s){memset(dist,0x3f,sizeof(dist));// 初始化起点到各点距离为无穷大
priority_queue<pair<int,int>, vector<pair<int,int>>, greater<>> q;// pair中第一项表示距离,第二项表示点的编号
q.push({0, s });
dist[s]=0;while(!q.empty()){int u = q.top().second;
q.pop();if(vis[u])continue;
vis[u]=true;for(auto e : G[u]){int v = e.v, w = e.w;if(dist[v]> dist[u]+ w){
dist[v]= dist[u]+ w;
q.push({ dist[v], v });}}}}// Luogu P3371 P4779intmain(){int n, m, s;
cin >> n >> m >> s;// n表示点数,m表示边数,s表示起点for(int i =0; i < m; i++){int u, v, w;
cin >> u >> v >> w;
G[u].push_back(Edge(v, w));}dijkstra(s);for(int i =1; i <= n; i++){if(dist[i]== INF) cout <<(1<<31)-1<<' ';// 无法到达else cout << dist[i]<<' ';}
cout << endl;return0;}
floyd
#include<iostream>#include<cstring>usingnamespace std;constint INF =0x3f3f3f3f;constint MAXN =1005;int d[MAXN][MAXN];// 记录所有点对之间的最短路径int n, m;voidfloyd(){for(int k =1; k <= n; k++){for(int i =1; i <= n; i++){for(int j =1; j <= n; j++){
d[i][j]=min(d[i][j], d[i][k]+ d[k][j]);}}}}// NC14697intmain(){int D;
cin >> n >> m >> D;// 初始化距离矩阵,注意自己到自己的距离为0memset(d,0x3f,sizeof(d));for(int i =1; i <= n; i++){
d[i][i]=0;}// 读入边权for(int i =1; i <= m; i++){int a, b, w;
cin >> a >> b >> w;
d[a][b]=min(d[a][b], w);}floyd();int ans =0;for(int i =1; i <= n; i++){for(int j =1; j <= n; j++){if(d[i][j]== D) ans++;}}
cout << ans << endl;return0;}
topo
#include<iostream>#include<vector>#include<queue>usingnamespace std;constint N =1e5+5;
vector<int> G[N];// 邻接表存储图int in_degree[N];// 记录每个点的入度
vector<int>topo_sort(int n){
vector<int> res;// 记录排序结果
queue<int> q;// 存储入度为0的点for(int i =1; i <= n; i++){if(in_degree[i]==0) q.push(i);// 将入度为0的点加入队列中}while(!q.empty()){int u = q.front();
q.pop();
res.push_back(u);for(auto v : G[u]){
in_degree[v]--;// 减去当前点的出边,相当于将它的邻居节点入度减一if(in_degree[v]==0) q.push(v);// 如果相邻节点的入度变成了0,加入队列中}}return res;}intmain(){int n, m;
cin >> n >> m;for(int i =0; i < m; i++){int u, v;
cin >> u >> v;
G[u].push_back(v);
in_degree[v]++;// 将每个点的入度加一}
vector<int> res =topo_sort(n);if(res.size()== n){// 如果排序后节点数和原始节点数相等,说明拓扑排序成功for(auto u : res){
cout << u <<' ';}}else{
cout <<"There is a cycle in the graph."<< endl;// 存在环,拓扑排序失败}return0;}