版权声明:https://blog.csdn.net/qq_41730082 https://blog.csdn.net/qq_41730082/article/details/85396638
题目链接
最小树形图讲解
这题需要调用freopen()函数
简单的最小树形图,但是这次得输出路径,就是选取了哪些边,这可处理起来就麻烦了,我们按照最小树形图的选取的时候,一开始选择的必然是最短路径,但是,这样的话,我们无可避免会选取到环的形式,那么就得删除环,于是,就是在最小树形图的步骤中进行处理了。
在最小树形图的处理过程中,我们有求最短弧、检查最短弧、以及收缩环的这么几个步骤,我们在收缩环的过程中,会直接加上最短弧的(优化过后——即当非第一次进入的时候,再选取的时候就是减去之前环中对应点的最下入边的),那么,我们会直接加进去这条边,但这条边或许并不是最优的边,我们在这之后,可能会寻找到更优的解,使得删除掉这条边,那怎么办?我们对应的删除边,并且,会加入边,对于每条要新加入的边,做一个判断,上一个改点的最小入边是哪个?并且将会去删除它,以达到加入新边的作用,之后,可能也会遇到删除新边的可能,所以对于加入的边,我们可能还会再删除它,因为,它可能又成了构成新环上的边了,那么,我们的图就是这样的,从后面开始,向前面衍生的过程了,当推到最小树形图的时候,就是返回展开图的时候了。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN = 1e6 + 7;
int N, M;
struct Eddge
{
int u, v, val, id, real;
Eddge(int a=0, int b=0, int c=0, int d=0, int f=0):u(a), v(b), val(c), id(d), real(f) {}
}edge[maxN];
int id[maxN], vis[maxN], in[maxN], pre[maxN], las_Eddge[maxN], used[maxN] = {0}, add_E[maxN] = {0}, dele_E[maxN] = {0};
int Dir_MST(int root, int V, int E)
{
int ans = 0, E_id = E;
while(true)
{
for(int i=1; i<=V; i++) in[i] = INF;
for(int i=1; i<=E; i++)
{
int u = edge[i].u, v = edge[i].v;
if(u != v && in[v] > edge[i].val)
{
in[v] = edge[i].val;
pre[v] = u;
las_Eddge[v] = edge[i].id;
}
}
for(int i=1; i<=V; i++)
{
if(i == root) continue;
if(in[i] == INF) return -1;
}
int cnt = 0;
memset(id, -1, sizeof(id)); memset(vis, -1, sizeof(vis));
in[root] = 0;
for(int i=1; i<=V; i++)
{
ans += in[i];
if(i != root) used[las_Eddge[i]]++;
int v = i;
while(vis[v] != i && id[v] == -1 && v != root)
{
vis[v] = i;
v = pre[v];
}
if(id[v] == -1 && v != root)
{
cnt++;
for(int u=pre[v]; u!=v; u=pre[u]) id[u] = cnt;
id[v] = cnt;
}
}
if(cnt == 0) break;
for(int i=1; i<=V; i++) if(id[i] == -1) id[i] = ++cnt;
for(int i=1; i<=E; i++)
{
int u = edge[i].u, v = edge[i].v;
edge[i].u = id[u]; edge[i].v = id[v];
if(id[u] != id[v])
{
edge[i].val -= in[v];
dele_E[++E_id] = las_Eddge[v];
add_E[E_id] = edge[i].id;
edge[i].id = E_id;
}
}
V = cnt;
root = id[root];
}
for(int i=E_id; i>E; i--)
{
if(used[i])
{
used[dele_E[i]]--;
used[add_E[i]]++;
}
}
return ans;
}
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
scanf("%d%d", &N, &M);
for(int i=1; i<=M; i++)
{
scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].val);
edge[i].id = i; edge[i].real = edge[i].val;
}
int ans = Dir_MST(1, N, M);
if(ans == -1 || ans == 0) { printf("%d\n", ans); return 0; }
printf("%d\n", ans);
bool flag = false;
for(int i=1; i<=M; i++)
{
if(used[i] && edge[i].real)
{
if(flag) printf(" ");
else flag = true;
printf("%d", i);
}
}
printf("\n");
return 0;
}