1. 图的存储
2. 并查集
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int p[N];
int n, m;
int find(int x)
{
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i ++ ) p[i] = i;
while (m -- )
{
char op;
int a, b;
cin >> op >> a >> b;
if(op == 'M') p[find(a)] = find(b);
else
{
if(find(a) == find(b)) puts("Yes");
else puts("No");
}
}
return 0;
}
3. 最小生成树
kruskal算法可以解决大多数问题
- 将所有便权重排序
- 从小到大将不连通的边连接起来(利用并查集)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2e5 + 10;
int n, m;
int p[N];
struct Edge
{
int a, b, w;
bool operator < (const Edge &W)const
{
return w < W.w;
}
}edge[N];
int find(int x) // 并查集
{
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i ++ ) p[i] = i;
for (int i = 0; i < m; i ++ )
{
int a, b, w;
cin >> a >> b >> w;
edge[i] = {a, b, w};
}
sort(edge, edge + m);
int res = 0, cnt = 0;
for (int i = 0; i < m; i ++ )
{
int a = edge[i].a, b = edge[i].b, w = edge[i].w;
if(find(a) != find(b))
{
res += w;
cnt ++;
p[find(a)] = find(b);
}
}
// cout << cnt;
if(cnt < n - 1) cout << "impossible" << endl;
else cout << res << endl;
return 0;
}
4. 最短路径
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 510;
int n, m;
int g[N][N]; //稠密图一般使用邻接矩阵
int dist[N]; //记录每个节点距离起点的距离
bool st[N]; //True表示已经确定最短路 属于s集合
int dijkstra() {
//所有节点距离起点的距离初始化为无穷大
memset(dist, 0x3f, sizeof dist);
//起点距离自己的距离为零
dist[1] = 0;
//迭代n次,每次可以确定一个点到起点的最短路
for (int i = 0; i < n; ++i) {
int t = -1;
//t的作用?
for (int j = 1; j <= n; ++j) {
//不在s集合,并且
//如果没有更新过,则进行更新, 或者发现更短的路径,则进行更新
if (!st[j] && (t == -1 || dist[j] < dist[t])) {
t = j;
}
}
//加入到s集合中
st[t] = true;
//找到了距离最小的点t,并用最小的点t去更新其他的点到起点的距离
for (int j = 1; j <= n; ++j) {
dist[j] = min(dist[j], dist[t] + g[t][j]);
}
}
// 如果起点到达不了n号节点,则返回-1
if (dist[n] == 0x3f3f3f3f) return -1;
// 返回起点距离n号节点的最短距离
return dist[n];
}
int main() {
cin >> n >> m;
//所有节点之间的距离初始化为无穷大
memset(g, 0x3f, sizeof g);
// 0x3f 0x3f3f3f3f 的区别?
while (m--) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
g[a][b] = min(g[a][b], c); //如果有重边,请保留权值最小的一条边
}
cout << dijkstra() << endl;
return 0;
}
5. 拓扑排序
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
vector<int> e[N];
vector<int> ans;
int d[N]; //统计入度
int n, m;
bool topu()
{
queue<int> q;
for(int i = 1; i <= n ; i++)
if(!d[i]) q.push(i);
while(q.size())
{
int t = q.front();
// cout << t << endl;
ans.push_back(t);
q.pop();
for(int i = 0; i < e[t].size(); i++)
{
int j = e[t][i];
if(-- d[j] == 0) q.push(j);
}
}
return ans.size() == n;
}
int main()
{
cin >> n >> m;
while(m -- )
{
int a, b;
cin >> a >> b;
e[a].push_back(b);
d[b] ++ ;
}
// for(int i = 1; i <= n; i++)
// cout << i << " " << d[i] << endl;
// topu();
if(!topu()) puts("-1");
else
{
for(auto c : ans) cout << c << " ";
cout << endl;
}
return 0;
}