图论
并查集
卡码网题目链接(ACM模式)
#include <bits/stdc++.h>
using namespace std;
int find(int x, vector<int>& root) {
int t = x;
while (root[t] != t) {
t = root[t];
}
int ans = t;
t = x;
while (root[t] != t) {
int tmp = root[t];
root[t] = ans;
t = tmp;
}
return ans;
}
bool joined(int x, int y, vector<int>& root) {
if (x == y) return true;
int x_root = find(x, root);
int y_root = find(y, root);
return x_root == y_root;
}
void join(int x, int y, vector<int>& root) {
if (x == y) return ;
int x_root = find(x, root);
int y_root = find(y, root);
root[x_root] = y_root;
}
int main() {
int n;
cin >> n;
std::vector<int> root(n + 1);
for (int i = 1; i <= n; ++i) {
root[i] = i;
}
for (int i = 1; i <= n ;++i) {
int s, e;
cin >> s >> e;
if (joined(s, e, root)) {
cout << s << " " << e << endl;
return 0;
} else {
join(s, e, root);
}
}
}
拓扑排序
卡码网:117. 软件构建
#include <bits/stdc++.h>
using namespace std;
vector<int> topo() {
int M, N, s, e;
cin >> N >> M;
vector<vector<int>> G(N, vector<int>(N, 0));
vector<int> path, in(N, 0);
queue<int> q;
while (M--) {
cin >> s >> e;
G[s][e] = 1;
++in[e];
}
for (int i = 0; i < N; ++i) {
if (in[i] == 0) {
q.push(i);
}
}
while (!q.empty()) {
int v = q.front(); q.pop();
path.push_back(v);
for (int i = 0; i < N; ++i) {
if (G[v][i]) {
if (--in[i] == 0) {
q.push(i);
}
}
}
}
if (path.size() == N) return path;
else return {};
}
int main() {
auto path = topo();
if (path.size()) {
for (int i = 0; i < path.size() - 1; ++i) {
cout << path[i] << " ";
}
cout << path.back() << endl;
} else {
cout << -1 << endl;
}
}
最小生成树prim
卡码网:53. 寻宝
#include <bits/stdc++.h>
using namespace std;
pair<bool, int> prim(const int V, const vector<vector<int>>& G, int start = 1) {
vector<int> joined(V + 1, 0);
vector<int> dist(V + 1, INT_MAX);
dist[start] = 0;
int totalCost = 0;
int joinedNodes = 0;
for (int i = 1; i <= V; ++i) {
int v = -1, minDist = INT_MAX;
for (int i = 1; i <= V; ++i) {
if (dist[i] < minDist && joined[i] == 0) {
v = i;
minDist = dist[i];
}
}
if (v == -1) {
break;
}
++joinedNodes;
totalCost += minDist;
joined[v] = 1;
for (int j = 1; j <= V; ++j) {
if (joined[j] == 0 && G[v][j] < dist[j] ) {
dist[j] = G[v][j];
}
}
}
return {joinedNodes == V, totalCost};
}
int main() {
int V, E;
cin >> V >> E;
vector<vector<int>> G(V + 1, vector<int>(V + 1, INT_MAX));
while (E--) {
int s, e, cost;
cin >> s >> e >> cost;
if (G[s][e] > cost) {
G[s][e] = G[e][s] = cost;
}
}
auto [f, totalCost] = prim(V, G);
if (f) cout << totalCost << endl;
}
最小生成树kruskal
卡码网:53. 寻宝
#include <bits/stdc++.h>
using namespace std;
struct Edge {
int start, end, val;
bool operator < (const Edge& rhs) { return val < rhs.val; }
};
class UnionSet {
public:
UnionSet(size_t v) : V(v), father(V + 1) {
for (int i = 1; i <= V; ++i) {
father[i] = i;
}
}
bool isSame(int u, int v) {
return u == v || find(u) == find(v);
}
int find(int u) {
return father[u] == u ? u : father[u] = find(father[u]);
}
bool join(int u, int v) {
int uf = find(u);
int vf = find(v);
if (uf == vf) return false;
father[uf] = vf;
return true;
}
bool isOnlyOne() {
bool f = true;
for (int i = 1; i <= V; ++i) {
if (!isSame(i, 1)) {
f = false;
break;
}
}
return f;
}
private:
size_t V;
vector<int> father;
};
int kruskal() {
int V, E;
int s, e, v;
cin >> V >> E;
int totalCost = 0;
vector<Edge> edges;
edges.reserve(E);
UnionSet unionSet(V);
while (E--) {
cin >> s >> e >> v;
edges.push_back(Edge{.start = s, .end = e, .val = v});
}
sort(edges.begin(), edges.end());
for (const Edge& edge : edges) {
if (unionSet.join(edge.start, edge.end)) {
totalCost += edge.val;
}
}
if (unionSet.isOnlyOne()) return totalCost;
else return -1;
}
int main() {
int totalCost = kruskal();
cout << totalCost << endl;
}
单源最短路径dijkstra
卡码网:47. 参加科学大会
#include <bits/stdc++.h>
using namespace std;
int dijkstra(int start = 1) {
int N, M, S, E, V;
cin >> N >> M;
vector<vector<int>> G(V + 1, vector<int>(N + 1, INT_MAX));
vector<int> visited(N + 1, 0);
vector<int> dist(N + 1, INT_MAX);
dist[start] = 0;
while (M--) {
cin >> S >> E >> V;
if (G[S][E] > V) {
G[S][E] = V;
}
}
for (int i = 1; i <= N; ++i) {
int v = -1, minDist = INT_MAX;
for (int i = 1; i <= N; ++i) {
if (dist[i] < minDist && visited[i] == 0) {
v = i;
minDist = dist[i];
}
}
if (v == -1) {
break;
}
visited[v] = 1;
for (int j = 1; j <= N; ++j) {
if (G[v][j] != INT_MAX && visited[j] == 0 && dist[v] + G[v][j] < dist[j] ) {
dist[j] = dist[v] + G[v][j];
}
}
}
return dist[N] == INT_MAX ? -1 : dist[N];
}
int main() {
cout << dijkstra() << endl;
}
多源最短路径floyd
卡码网:97. 小明逛公园
#include <bits/stdc++.h>
using namespace std;
vector<int> floyd() {
int N, M, u, v, w, numOfPlans;
cin >> N >> M;
vector<vector<int>> G(N + 1, vector<int>(N + 1, INT_MAX));
vector<int> ans;
vector<pair<int, int>> plans;
while (M--) {
cin >> u >> v >> w;
if (G[u][v] > w) {
G[u][v] = G[v][u] = w;
}
}
cin >> numOfPlans;
while (numOfPlans--) {
cin >> u >> v;
plans.emplace_back(u, v);
}
for (int k = 1; k <= N; ++k) {
for (int i = 1; i <= N; ++i) {
for (int j = 1; j <= N; ++j) {
if (G[i][k] != INT_MAX && G[k][j] != INT_MAX && G[i][k] + G[k][j] < G[i][j]) {
G[i][j] = G[i][k] + G[k][j];
}
}
}
}
for (const auto& plan : plans) {
ans.push_back(G[plan.first][plan.second] == INT_MAX ? -1 : G[plan.first][plan.second]);
}
return ans;
}
int main() {
auto dist = floyd();
for (const int d : dist) {
cout << d << endl;
}
return 0;
}
单源最短路径SPFA(负环)
卡码网:95. 城市间货物运输 II
#include <bits/stdc++.h>
using namespace std;
struct Edge {
int s, t, v;
Edge(int s, int t, int v) : s(s), t(t), v(v) {}
};
void SPFA() {
int n, m, s, t, v;
bool circle = false;
cin >> n >> m;
int start = 1, end = n;
vector<list<Edge>> G(n + 1);
vector<int> count(n + 1, 0), dist(n + 1, INT_MAX);
queue<int> q;
while (m--) {
cin >> s >> t >> v;
G[s].push_back(Edge(s, t, v));
}
dist[start] = 0;
count[start]++;
q.push(start);
while (!q.empty()) {
int node = q.front(); q.pop();
for (const Edge& edge : G[node]) {
int from = node, to = edge.t, weight = edge.v;
if (dist[to] > dist[from] + weight) {
dist[to] = dist[from] + weight;
q.push(to);
++count[to];
if (count[to] == n) {
circle = true;
queue<int> tmpq;
q.swap(tmpq); // 清空队列,防止死循环
break;
}
}
}
}
if (circle) {
cout << "circle" << endl;
} else if (dist[end] == INT_MAX) {
cout << "unconnected" << endl;
} else {
cout << dist[end] << endl;
}
}
int main() {
SPFA();
}