有向图的最小生成树,用的算法是朱刘算法
有向图的最小生成树
定义
- 恰好有一个入度为0的节点,该节点被称为根节点
- 其他的节点入度为1
- 从根节点可以到达任意的节点
最重要的思想
资料及代码的参考来源
最小树形图——朱刘算法(Edmonds)
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 1010
#define MAXM 1000000+10
#define INF 0x3f3f3f3f
#include <iostream>
using namespace std;
struct Edge
{
int from, to, cost;
};
Edge edge[MAXM];
int pre[MAXN];
int vis[MAXN];
int id[MAXN];
int in[MAXN];
int N, M;
int zhuliu(int root, int n, int m, Edge *edge)
{
int res = 0, u, v;
while(1)
{
for(int i = 0; i < n; i++)
in[i] = INF;
for(int i = 0; i < m; i++)
{
Edge E = edge[i];
if(E.from != E.to && E.cost < in[E.to])
{
pre[E.to] = E.from;
in[E.to] = E.cost;
}
}
for(int i = 0; i < n; i++)
if(i != root && in[i] == INF)
return -1;
int tn = 0;
memset(id, -1, sizeof(id));
memset(vis, -1, sizeof(vis));
in[root] = 0;
for(int i = 0; i < n; i++)
{
res += in[i];
v = i;
while(vis[v] != i && id[v] == -1 && v != root)
{
vis[v] = i;
v = pre[v];
}
if(v != root && id[v] == -1)
{
for(int u = pre[v]; u != v; u = pre[u])
id[u] = tn;
id[v] = tn++;
}
}
if(tn == 0) break;
for(int i = 0; i < n; i++)
if(id[i] == -1){
id[i] = tn++;
}
for(int i = 0; i < m; i++)
{
v = edge[i].to;
edge[i].from = id[edge[i].from];
edge[i].to = id[edge[i].to];
if(edge[i].from != edge[i].to)
edge[i].cost -= in[v];
}
n = tn;
root = id[root];
}
return res;
}
void getMap(){
int u, v, w;
for(int i=0; i<M; i++){
scanf("%d%d%d", &u, &v, &w);
edge[i] = Edge{u-1, v-1, w};
}
}
int main()
{
while(scanf("%d%d", &N, &M) != EOF)
{
getMap();
int ans = zhuliu(0, N, M, edge);
if(ans == -1)
printf("-1\n");
else
printf("%d\n", ans);
}
return 0;
}
未解决的问题