Road Repairs 【CodeForces - 240E】【最小树形图+边输出】

版权声明: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;
}

猜你喜欢

转载自blog.csdn.net/qq_41730082/article/details/85396638