1. 程式人生 > >Road Repairs 【CodeForces - 240E】【最小樹形圖+邊輸出】

Road Repairs 【CodeForces - 240E】【最小樹形圖+邊輸出】

題目連結

最小樹形圖講解

這題需要呼叫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;
}