Compare commits

...

2 Commits

Author SHA1 Message Date
429a62a245 添加拓扑排序、最小生成树算法 2025-06-06 10:48:58 +08:00
ef5480b44f dijkstra及并查集算法更新 2025-06-06 10:48:57 +08:00
6 changed files with 251 additions and 65 deletions

View File

@ -1,35 +1,35 @@
class Solution {
public:
int diskstra(vector<vector<int>>& edges, int n, int start, int end) {
vector<vector<int>> graph(n, vector<int>(n, INT_MAX / 2));
// === 建图 ===
for (auto& [from, to, dist]: edges) {
graph[from][to] = dist;
}
int diskstra(vector<vector<int>>& edges, int n, int start, int end) {
vector<vector<int>> graph(n, vector<int>(n, INT_MAX / 2));
for (auto& edge : edges) {
int from = edge[0], to = edge[1], dist = edge[2];
graph[from][to] = dist; // build the graph
}
vector<int> distance(n, INT_MAX/2), visited(n, 0);
distance[start] = 0;
while (true) {
int next_node = -1;
for (int node = 0; node < n; node++) {
if (visited[node]) {
continue; // 不重复更新
}
if (next_node < 0 || distance[next_node] > distance[node]) {
next_node = node; // 寻找移动路径最小的节点
}
}
vector<int> distance(n, INT_MAX / 2), visited(n, 0);
distance[start] = 0;
while (true) {
int next_node = -1;
for (int node = 0; node < n; node++) {
if (visited[node]) {
continue; // update non-repeatedly
}
if (next_node < 0 || distance[next_node] > distance[node]) {
next_node = node; // find the node with the smallest moving path
}
}
if (next_node < 0 || distance[next_node] == INT_MAX / 2) {
break; // 找不到节点
}
if (next_node < 0 || distance[next_node] == INT_MAX / 2) {
break; // cannot find the node
}
visited[next_node] = 1;
for (int node = 0; node < n; node++) {
// 根据最近节点路径更新其余节点移动路径
distance[node] = min(distance[node], distance[next_node] + graph[next_node][node]);
}
}
return distance[end] == INT_MAX / 2 ? -1 : distance[end];
}
visited[next_node] = 1;
for (int node = 0; node < n; node++) {
// update the moving paths of the remaining nodes based on the nearest node
distance[node] = min(distance[node], distance[next_node] + graph[next_node][node]);
}
}
return distance[end] == INT_MAX / 2 ? -1 : distance[end];
}
};

114
minimum-spanning-tree.cpp Normal file
View File

@ -0,0 +1,114 @@
class MST
{
/**
* Minumum Spanning Tree
*
*/
private:
vector<int> _pre; // pre-node
vector<int> _size; // size of node
/*!
* @brief : finding function of union set
* @param [x] : node index
* @retval : parent node
*/
int find(int x)
{
if (_pre[x] == x)
return x;
_pre[x] = find(_pre[x]);
return _pre[x];
}
public:
/*!
* @brief : prim minimum spanning tree algorithm
* @param [num_nodes] : number of nodes
* @param [connections] : inter-node connection distance [start<72><74>end<6E><64>distance]
* @retval : minimum weighted-sum
*/
int prim(int num_nodes, vector<vector<int>>& connections)
{
vector<vector<pair<int, int>>> edges(n);
for (size_t i = 0; i < connections.size(); i++) {
int city_a = connections[i][0], city_b = connections[i][1];
int cost = connections[i][2];
edges[city_a].push_back(make_pair(city_b, cost));
edges[city_b].push_back(make_pair(city_a, cost));
}
set<int> intree; // set of visited node
vector<pair<int, int>> out_edges; // external edge
out_edges.push_back(make_pair(0, 0)); // target node
int ans = 0;
// iterate over all outward expanding edges until all nodes are visited
while (out_edges.size() != 0 && intree.size() != num_nodes)
{
// find the edge with minimal weight
vector<pair<int, int>>::iterator iter = min_element(out_edges.begin(), out_edges.end(), [&](pair<int, int>& elem1, pair<int, int>elem2)
{
return elem1.second < elem2.second;
});
pair<int, int> out_edge = *iter;
out_edges.erase(iter);
// add unvisited node
if (intree.find(out_edge.first) == intree.end())
{
intree.insert(out_edge.first);
ans += out_edge.second;
for (pair<int, int> edge : edges[out_edge.first])
{
out_edges.push_back(make_pair(edge.first, edge.second));
}
}
}
if (intree.size() != num_nodes)
return -1; // not exist if two nodes is not connected
return ans;
}
/*!
* @brief : Kruskal MST algorithm
* @param [num_nodes] : Number of nodes
* @param [connections] : Inter-node connection distance [start<72><74>end<6E><64>distance]
* @retval : Minimum weighted-sum
*/
int kruskal(int numNodes, vector<vector<int>>& connections)
_pre.resize(numNodes), _size.resize(numNodes, 1);
iota(_pre.begin(), _pre.end(), 0);
// sort with the distance
sort(connections.begin(), connections.end(), [&](vector<int>& elem1, vector<int>& elem2) {
return elem1.at(2) < elem2.at(2);
});
int ans = 0; // minimum weighted-sum
int edge_count = 0; // number of visited nodes
for (size_t i = 0; i < connections.size(); i++) {
int x = find(connections[i][0]), y = find(connections[i][1]);
// Union find set
if (x != y) {
if (_size[x] > _size[y]) {
swap(x, y);
}
_pre[x] = y;
_size[y] += _size[x];
ans += connections[i][2];
edge_count++;
if (edge_count == numNodes - 1) {
return ans;
}
}
}
return -1; // not exist if two nodes is not connected
}
};

72
topological-sorting.cpp Normal file
View File

@ -0,0 +1,72 @@
class Solution
{
private:
enum class STATUS
{
UN_VISITED,
IN_SEARCHING,
FINISHED
};
vector<vector<int>> edges;
vector<Status> visited;
vector<int> sequence;
bool find_cycle = false; // cycle
/**
* @brief deep first search
* @param[in] node index
*
*/
void deepFirstSearch(int node)
{
visited[node] = Status::SEARCHING;
for (int neighbor : edges[node]) {
if (visited[neighbor] == Status::UNVISITED) {
deepFirstSearch(neighbor);
if (find_cycle) {
return; // unsolvable
}
}
else if (visited[neighbor] == Status::SEARCHING) {
find_cycle = true;
return;
}
}
visited[node] = Status::FINISH;
sequence.push_back(node);
}
public:
/**
* @brief topological sequence
* @param[in] number of nodes
* @param[in] node connection
* @retval sequence
*/
vector<int> findTopologicalOrder(int numNodes, vector<vector<int>>& linkage)
{
edges.resize(numNodes);
visited.resize(numNodes, Status::UNVISITED);
// generate adjacency list
for (const auto& info : linkage) {
edges[info[1]].push_back(info[0]);
}
// deep first search to determine the topological sequence
for (int i = 0; i < numNodes && !find_cycle; ++i) {
if (visited[i] == Status::UNVISITED) {
deepFirstSearch(i);
}
}
if (find_cycle) {
return vector<int>(); // unsolvable for cycle
}
reverse(sequence.begin(), sequence.end());
return sequence;
}
};

36
union-find-sets.cpp Normal file
View File

@ -0,0 +1,36 @@
class UnionFind {
vector<int> _pre; // 代表元
vector<int> _rank; // 集合的秩
public:
UnionFind(int n) : _pre(n), _rank(n, 1) {
iota(_pre.begin(), _pre.end(), 0);
//ranges::iota(_pre, 0);
}
int find(int x) {
return _pre[x] == x ? x : _pre[x] = find(_pre[x]);
}
bool same(int x, int y) {
return find(x) == find(y);
}
bool merge(int from, int to) {
int x = find(from), y = find(to);
if (x == y) {
return false;
}
if (_rank[x] < _rank[y]) {
_pre[x] = y;
}
else if (_rank[x] > _rank[y]) {
_pre[y] = x;
}
else {
_pre[x] = y;
_rank[y]++;
}
return true;
}
};

View File

@ -1,36 +0,0 @@
class UnionFind {
vector<int> _pre; // 代表元
vector<int> _rank; // 集合的秩
public:
UnionFind(int n) : _pre(n), _rank(n, 1), cc(n) {
// iota(fa.begin(), fa.end(), 0);
ranges::iota(fa, 0);
}
int find(int x) {
return _pre[x] == x ? x : _pre[x] = fint(_pre[x]);
}
bool same(int x, int y) {
return find(x) == find(y);
}
bool merge(int from, int to) {
int x = find(from), y = find(to);
if (x == y) {
return false; //同一集合不做合并
}
if (_rank[x] < _rank[y]) {
_pre[x] = y;
}
else if (_rank[x] > _rank[y]) {
_pre[y] = x;
}
else {
_pre[x] = y;
_rank[y]++;
}
return true;
}
};