Road Repairs 【CodeForces - 240E】【最小樹形圖+邊輸出】
阿新 • • 發佈:2019-01-06
題目連結
最小樹形圖講解
這題需要呼叫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; }