24h購物| | PChome| 登入
2013-11-09 20:06:06| 人氣3,086| 回應0 | 上一篇 | 下一篇

[POJ][樹分治] 1741 - Tree

推薦 0 收藏 0 轉貼0 訂閱站台

Description

Give a tree with n vertices,each edge has a length(positive integer less than 1001).
Define dist(u,v)=The min distance between node u and v.
Give an integer k,for every pair (u,v) of vertices is called valid if and only if dist(u,v) not exceed k.
Write a program that will count how many pairs which are valid for a given tree.

Input

The input contains several test cases. The first line of each test case contains two integers n, k. (n<=10000) The following n-1 lines each contains three integers u,v,l, which means there is an edge between node u and v of length l.
The last test case is followed by two zeros.

Output

For each test case output the answer on a single line.

Sample Input

5 4
1 2 3
1 3 1
1 4 2
3 5 1
0 0

Sample Output

8



這題的思路並不難。

考慮一個 rooted tree,決定所有路徑經過 root 的,接下來分別對於子樹再做即可。
現在著重於如何有效的找到樹的重心,否則隨便找到一個點當作 root 演算法可能會退化至 O(n^2)。

樹的重心:重心必須符合其所有子樹的最大值要最小。

如果能有效地查找一個樹的重心,將可以在 O(n logn) 解決這一道問題。

計算所有路徑經過 root 且長度小於等於 k 的個數時,我們需要稍微使用一下排容原理。

備註,我只不過稍微寫慢了一點,就一直死活地停留在 TLE 那裏。

#include <stdio.h>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
struct Edge {
    int to, w;
    Edge(int a=0, int b=0):
        to(a), w(b) {}
};
int N, K;
vector<Edge> g[10005];
int done[10005];
int mxsubtree[10005], sizesubtree[10005], f[10005];
int visited[10005], vIdx;
int dist[10005], p[10005];
int root;
int dfs(int nd, int p) {
    int i, sum = 1, t;
    mxsubtree[nd] = 0;
    visited[vIdx++] = nd;
    for(i = 0; i < g[nd].size(); i++) {
        if(g[nd][i].to == p || done[g[nd][i].to])
            continue;
        t = dfs(g[nd][i].to, nd);
        sum += t;
        mxsubtree[nd] = max(mxsubtree[nd], t);
    }
    sizesubtree[nd] = sum;
    f[nd] = max(mxsubtree[nd], N-sizesubtree[nd]);
    if(f[nd] < f[root])    root = nd;
    return sum;
}    
void dfs2(int nd, int pp, int d) {
    p[vIdx++] = d;
    int i;
    for(i = 0; i < g[nd].size(); i++) {
        if(g[nd][i].to == pp || done[g[nd][i].to])
            continue;
        dfs2(g[nd][i].to, nd, d+g[nd][i].w);
    }
}  
int bfsCalc(int root, int init) {// find # of path length <= K which pass root.
    int i, j;
    vIdx = 0;
    dfs2(root, -1, init);
    sort(p, p+vIdx);
    int pairCnt = 0;
    for(i = 0, j = vIdx-1; i < j;) {
        if(p[i] + p[j] <= K)
            pairCnt += j - i, i++;
        else
            j--;
    }
    return pairCnt;
}
int DP(int node) {
    int i;
    int ret = bfsCalc(node, 0);
    done[node] = 1;
    for(i = g[node].size()-1; i >= 0; i--) {
        if(done[g[node][i].to])
            continue;
        ret -= bfsCalc(g[node][i].to, g[node][i].w);
        N = sizesubtree[g[node][i].to];
        root = 0, f[0] = N+1;
        dfs(g[node][i].to, -1);
        ret += DP(root);
    }
    return ret;
}
int main() {
    /*freopen("in.txt","r+t",stdin);
    freopen("out.txt","w+t",stdout);*/
    int i, x, y, w;
    while(scanf("%d %d", &N, &K) == 2 && N) {
        for(i = 1; i <= N; i++)
            g[i].clear(), done[i] = 0;
        for(i = N-2; i >= 0; i--) {
            scanf("%d %d %d", &x, &y, &w);
            g[x].push_back(Edge(y, w));
            g[y].push_back(Edge(x, w));
        }
        f[root = 0] = N;
        dfs(1, -1);
        int ret = DP(root);
        printf("%d\n", ret);
    }
    return 0;
}

台長: Morris
人氣(3,086) | 回應(0)| 推薦 (0)| 收藏 (0)| 轉寄
全站分類: 教育學習(進修、留學、學術研究、教育概況) | 個人分類: 其他題目 |
此分類下一篇:[POJ][多重背包] 1742 - Coins
此分類上一篇:[高等演算法][作業一] 討論

是 (若未登入"個人新聞台帳號"則看不到回覆唷!)
* 請輸入識別碼:
請輸入圖片中算式的結果(可能為0) 
(有*為必填)
TOP
詳全文