bzoj1060: [ZJOI2007]時態同步(貪心)
題目描述:小Q在電子工藝實習課上學習焊接電路板。一塊電路板由若干個元件組成,我們不妨稱之為節點,並將其用數字1,2,3….進行標號。電路板的各個節點由若干不相交的導線相連線,且對於電路板的任何兩個節點,都存在且僅存在一條通路(通路指連線兩個元件的導線序列)。在電路板上存在一個特殊的元件稱為“激發器”。當激發器工,產生一個激勵電流,通過導線傳向每一個它所連線的節點。而中間節點接收到激勵電流後,得到資訊,並將該激勵流傳向與它連線並且尚未接收到激勵電流的節點。最終,激烈電流將到達一些“終止節點”——接收激勵電流之後不再轉發的節點。激勵電流在導線上的傳播是需要花費時間的,對於每條邊e,激勵電流通過它需要的時間為te,而節點接收到激勵電流後的轉發可以認為是在瞬間完成的。現在這塊電路板要求每一個“終止節點”同時得到激勵電路——即保持時態同步。由於當前的構造並不符合時態同步的要求,故需要通過改變連線線的構造。目前小Q有一個道具,使用一次該道具,可以使得激勵電流通過某條連線導線的時間增加一個單位。請問小Q最少使用多少次道具才可使得所有的“終止節點”時態同步?
輸入格式:第一行包含一個正整數N,表示電路板中節點的個數。第二行包含一個整數S,為該電路板的激發器的編。接下來N-1行,每行三個整數a , b , t。表示該條導線連線節點a與節點b,且激勵電流通過這條導線需要t個單位時間
輸出格式:僅包含一個整數V,為小Q最少使用的道具次數。
輸入樣例:
3
1
1 2 1
1 3 3
輸出樣例:
2
解析:聽說是樹形DP,但感覺一看就是個貪心啊。
最後點的時間大小肯定是耗時最多的點的大小,所以先一次dfs找出耗時最大的點的大小。
再對於每個點處理出它的子樹內還需要加的單位的最小值。
最後從根向葉子dfs一遍貪心累加就好了。
細節看程式碼。
程式碼如下:
#include<cstdio> #include<algorithm> #define ll long long using namespace std; const int maxn = 500005; int n, s; int hed[maxn << 1], nxt[maxn << 1], to[maxn << 1], val[maxn << 1], cnt; ll dep[maxn], tim, size[maxn], ans; int read(void) { char c; while (c = getchar(), c < '0' || c >'9'); int x = c - '0'; while (c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; return x; } void add(int x, int y, int v) { nxt[++ cnt] = hed[x]; hed[x] = cnt; to[cnt] = y; val[cnt] = v; } void dfs(int u, int pre) { //找出深度最大的點 for (int i = hed[u]; i ; i = nxt[i]) { int v = to[i]; if (v == pre) continue; dep[v] = dep[u] + val[i]; dfs(v, u); } } void dfs1(int u, int pre) { //處理出每個子樹中所需加上單位的最小值 int flag = 0; for (int i = hed[u]; i ; i = nxt[i]) { int v = to[i]; if (v == pre) continue; dfs1(v, u); flag = 1; size[u] = min(size[u], size[v]); } if (!flag) size[u] = tim - dep[u]; } void dfs2(int u, int pre, int add) { //add記錄下已經加了多少個單位 for (int i = hed[u]; i ; i = nxt[i]) { int v = to[i]; if (v == pre) continue; if (size[v] - add > 0) { //若現在加上的單位還不夠多,就繼續加 ans += size[v] - add; dfs2(v, u, size[v]); } else dfs2(v, u, add); } } int main() { n = read(); s = read(); for (int i = 1; i < n; ++ i) { int x = read(), y = read(), v = read(); add(x, y, v); add(y, x, v); } dfs(s, 0); for (int i = 1; i <= n; ++ i) if (dep[i] > tim) tim = dep[i]; for (int i = 1; i <= n; ++ i) size[i] = 2e9; dfs1(s, 0); dfs2(s, 0, 0); printf("%lld", ans); return 0; }