1. 程式人生 > >bzoj1060: [ZJOI2007]時態同步(貪心)

bzoj1060: [ZJOI2007]時態同步(貪心)

bzoj1060

題目描述:小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;
}