【POJ2152】Fire——树形DP

来源:互联网 发布:传奇怪物补丁算法 编辑:程序博客网 时间:2024/05/20 09:46

Fire

Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 1294 Accepted: 669

Description

Country Z has N cities, which are numbered from 1 to N. Cities are connected by highways, and there is exact one path between two different cities. Recently country Z often caught fire, so the government decided to build some firehouses in some cities. Build a firehouse in city K cost W(K). W for different cities may be different. If there is not firehouse in city K, the distance between it and the nearest city which has a firehouse, can’t be more than D(K). D for different cities also may be different. To save money, the government wants you to calculate the minimum cost to build firehouses.

Input

The first line of input contains a single integer T representing the number of test cases. The following T blocks each represents a test case.

The first line of each block contains an integer N (1 < N <= 1000). The second line contains N numbers separated by one or more blanks. The I-th number means W(I) (0 < W(I) <= 10000). The third line contains N numbers separated by one or more blanks. The I-th number means D(I) (0 <= D(I) <= 10000). The following N-1 lines each contains three integers u, v, L (1 <= u, v <= N,0 < L <= 1000), which means there is a highway between city u and v of length L.

Output

For each test case output the minimum cost on a single line.

Sample Input

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

Sample Output

2
1
2
2
3

Source

POJ Monthly,Lou Tiancheng

Translation

给一棵带权树,每个节点需要被覆盖,覆盖节点i的方法为一下二者之一:

  1. wi的价格在该点建消防站
  2. 在该点距离di的范围内有至少一个消防站

求覆盖整棵树的最小代价

Solution

记dp[i][j]表示第i号节点被j号节点覆盖,且i号节点的子树被全部覆盖的最小代价,best[i]表示将i号节点的子树全部覆盖的最小代价,dis[i][j]表示树上两点i,j间的距离
dis[i][j]可以用O(n2)的时间预处理
dp[i][j]和best[i]可以这样转移

dp[i][j]=w[j]+kimin(dp[k][j]w[j],best[k])

best[i]=minnj=1dp[i][j]

其中,由于每一个dp[k][j]都包含了w[j],所以我们在统计儿子时要将其去掉,并在最后加上
最后的答案便是best[root],root可以任定

Code

/*POJ2152Author:Johann*/#include <iostream>#include <cstdio>#include <cstdlib>#include <queue>#include <algorithm>#include <cmath>#include <iomanip>#include <cstring>using namespace std;#define rep(i, a, b) for(int i = (a); i <= (b); i++)#define red(i, a, b) for(int i = (a); i >= (b); i--)#define ll long longinline int read() {    char c = getchar(); int x = 0;    while(!isdigit(c)) c = getchar();    while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar(); }    return x;}const int N = 1500;const int inf = 1000000000;struct edge{    int from, to, len, nxt;}e[N * 2];int dp[N][N], dis[N][N];int head[N], best[N], vis[N], w[N], d[N], lst[N];int q[N];int T, n, tail = 0, cnt = 0;void addedge(int x, int y, int z) {    e[++tail].from = x;    e[tail].to = y;    e[tail].len = z;    e[tail].nxt = head[x];    head[x] = tail;}void work(int root) {    if (root == 1) lst[cnt = 1] = 1;    memset(vis, 0, sizeof(vis));    dis[root][root] = 0;     vis[root] = 1;    int l = 1, r = 1;    q[1] = root;    while(l <= r) {        int x = q[l]; l++;        for(int i = head[x]; i != -1; i = e[i].nxt) {            int v = e[i].to;            if (!vis[v]) {                vis[v] = 1;                 if (root == 1) lst[++cnt] = v;                dis[root][v] = dis[root][x] + e[i].len;                q[++r] = v;            }        }    }}void DP() {    memset(vis, 0, sizeof(vis));    red(k, n, 1) {        int u = lst[k];        vis[u] = 1;        best[u] = inf;        rep(j, 1, n) {            if (dis[u][j] > d[u]) {                dp[u][j] = inf;                continue;            }            dp[u][j] = 0;            for(int i = head[u]; i != -1; i = e[i].nxt) {                int v = e[i].to;                if (!vis[v]) continue;                dp[u][j] += min(dp[v][j] - w[j], best[v]);            }            dp[u][j] += w[j];            if (dp[u][j] < best[u]) best[u] = dp[u][j];        }    }}int main() {    scanf("%d", &T);    while(T--) {        tail = 0;        n = read();        rep(i, 1, n) w[i] = read();        rep(i, 1, n) d[i] = read();        rep(i, 1, n) head[i] = -1;        rep(i, 1, n - 1) {            int x = read(), y = read(), z = read();            addedge(x, y, z);            addedge(y, x, z);        }        rep(i, 1, n) work(i);        DP();        printf("%d\n", best[1]);    }    return 0;}

尾声

终于拿到新键盘了,写题的动力!
茶轴真棒!
千万不能把Codeforces的习惯带入POJ(可见BZOJ的优越),第一次体会到STL Queue被卡T的快感
陈启峰论文题……好吧的确不容易
老大在机房里开了监!控!
监!控!
重复一遍,HBH是心机婊

End.

0 0
原创粉丝点击