代码实现:
int par[MAXN], Rank[MAXN];
void init(int n) //初始化,将自身作为自己的父节点
{
for (int i = 0; i < n; i++)
{
par[i] = i;
Rank[i] = i;
}
}
int find(int x) //找到x的父节点
{
if (par[x] == x)return x;
else return x = find(par[x]);
}
void unite(int x,int y) //合并x和y的集合
{
x = find(x);
y = find(y);
if (x == y)return;
if (Rank[x] > Rank[y])
par[x] = y;
else
{
par[y] = x;
if (Rank[x] = Rank[y])Rank[x]++;
}
}
bool same(int x, int y) //判断二者的集合是否一致
{
return find(x) == find(y);
}
代码实现:
#include
#define INF 0x3f3f3f3
const int maxn = 1000;
using namespace std;
//从顶点from指向顶点to的权值为val的边
struct edge
{
int from; int to; int val;
};
edge es[maxn]; //边
int d[maxn], V, E; //V是顶点数,E是边数,d[i]存放点i的最短距离。
//求解从顶点s出发到所有点的最短距离
void Shortest_path(int s)
{
for (int i = 0; i < V; i++)d[i] = INF;
d[s] = 0;
while (true)
{
bool update = false;
for (int i = 0; i < E; i++)
{
edge e = es[i];
if (d[e.from] != INF && d[e.to] > d[e.from] + e.val)
{
d[e.to] = d[e.from] + e.val;
update = true;
}
}
if (!update)break;
}
}
检测负圈代码实现:
//如果返回true则说明存在负圈
bool find_negative_loop()
{
memset(d, 0, sizeof d);
for (int i = 0; i < V; i++)
{
for (int j = 0; j < E; j++)
{
edge e = es[j];
if (d[e.to] > d[e.from] + e.val)
{
d[e.to] = d[e.from] + e.val;
//若第V次还在更新说明存在负圈
if (i == V - 1)return true;
}
}
}
return false;
}
代码实现:
#include
#include
#define INF 0x3f3f3f
const int maxn = 1001;
using namespace std;
int val[maxn][maxn]; //val[i][j]表示边(i,j)的权值(不存在时这条边设为INF)
int d[maxn]; //顶点s出发的最短距离
bool used[maxn]; //已经使用过的图
int V; //顶点个数
//求从起点s出发到各个顶点的最短距离
void dijkstra(int s)
{
fill(d,d+V,INF);
fill(used, used + V, false);
d[s] = 0;
while (true)
{
int v = -1;
//在尚未使用过的点中选择距离最小的顶点
for (int u = 0; u < V; u++)
if (!used[u] && (v == -1 || d[u] < d[v]))v = u;
if (v == -1)break;
used[v] = true;
for (int u = 0; u < V; u++)
d[u] = min(d[u], d[v] + val[v][u]);
}
}
代码实现
#include
const int maxn = 1001;
using namespace std;
int d[maxn][maxn];
int V;
void warshall_floyd()
{
for (int k = 0; k < V; k++)
for (int i = 0; i < V; i++)
for (int j = 0; j < V; j++)
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}
代码实现:
int prevd[maxn];
//求从起点s出发到各个顶点的最短距离
void dijkstra(int s)
{
fill(d, d + V, INF);
fill(used, used + V, false);
fill(prevd, prevd + V, -1);
d[s] = 0;
while (true)
{
int v = -1;
//在尚未使用过的点中选择距离最小的顶点
for (int u = 0; u < V; u++)
if (!used[u] && (v == -1 || d[u] < d[v]))v = u;
if (v == -1)break;
used[v] = true;
for (int u = 0; u < V; u++)
if (d[u] > d[v] + val[v][u])
{
d[u] = d[v] + val[v][u];
prevd[u] = v;
}
}
}
代码实现:
int minval[maxn]; //已确定最短距离集合到结点v的距离
bool vis[maxn]; //判断结点是否已在最短距离集合
int val[maxn][maxn];//记录结点之间的权值
int V,E;
int prim()
{
fill(minval, minval + V, INF);
fill(vis, vis + V, false);
minval[0] = 0;
int ans = 0;
while (true)
{
int v = -1;
for (int u = 0; u < V; u++)
if (!vis[u] && (v == -1 || minval[u] < minval[v]))
v = u;
if (v == -1)break;
ans += minval[v];
vis[v] = true;
for (int u = 0; u < V; u++)
minval[u] = min(minval[u],val[v][u]);
}
return ans;
}
Kruskal
算法按照边的权值顺序从小到大查看一遍,如果不产生圈(重边等也在内),就把当前这条边加入到生成树之中。代码实现:
#define MAXN 10010
int V, E;
struct edge
{
int u, v, val;
}es[MAXN];
bool cmp(edge a, edge b)
{
return a.val < b.val;
}
int kruskal() {
sort(es, es + E, cmp); //将所有边按照权值大小,从小到大排序
init(V); //并查集的初始化,将每个节点当作一个集合,不断合并
int res = 0;
for (int i = 0; i < E; i++)
{
edge e = es[i];
if (!same(e.u, e.v)) //合并结点
{
unite(e.u, e.v);
res += e.val;
}
}
return res;
}