码迷,mamicode.com
首页 > 其他好文 > 详细

uva 12223(树形dp)

时间:2015-07-22 23:01:05      阅读:303      评论:0      收藏:0      [点我收藏+]

标签:

题意:一个城市有n个景点,景点和景点之间的路线形成一棵无根树(也就是有n-1条边),给出景点之间的花费,一个人可以任选一个景点住在那里,然后他每年都要固定去m个景点,给出这m个景点和要去的次数,这个人每次去了景点都会回家,问他一年为了观赏景点最少花费多少钱。
题解:想了好久,看看题解才完全理解。要先把无根树转化成有根树,默认让1成为根节点,然后先dfs把每个节点v当做根节点的子树的节点数统计一下在num[v]中,因为计算u-v边的走到次数就是以v为根节点的子树的节点数的个数乘边的权值乘2(来回),同时把f[1]也就是以1为根节点到想去的景点的花费得出(因为1没有父亲节点),这个过程是自底向上的。
然后dp中更新其余n-1个点的f[v]值,f[v]和自己父亲节点u的f[u]有关,可以想到,如果把居住地从u变成了v,花费变化其实只有u-v这条边,只要得到通过u-v这边的新次数,就可以直接更新f[v]值了,这个更新过程是自顶向下的。
状态转移方程:f[v] = f[u] - num[v] * 2 * w + (num[1] - num[v]) * 2 * w。
先把u通过v到其他节点的次数减掉,然后把v通过u到其他节点的次数加起来。

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 50005;
int n, m, vis[N];
vector<int> g[N];
vector<long long> w[N];
long long f[N], num[N], res;

void init() {
    memset(num, 0, sizeof(num));
    for (int i = 0; i <= n; i++) {
        g[i].clear();
        w[i].clear();
    }
}

void dp(int u) {
    vis[u] = 1;
    res = min(res, f[u]);
    for (int i = 0; i < g[u].size(); i++) {
        int v = g[u][i];
        long long ww = w[u][i];
        if (vis[v])
            continue;
        f[v] = f[u] - num[v] * 2 * ww + (num[1] - num[v]) * 2 * ww;
        dp(v);
    }
}

void dfs(int u) {
    vis[u] = 1;
    f[u] = 0;
    for (int i = 0; i < g[u].size(); i++) {
        int v = g[u][i];
        long long ww = w[u][i];
        if (vis[v])
            continue;
        dfs(v);
        num[u] += num[v];
        f[u] += f[v] + num[v] * ww * 2;
    }
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        scanf("%d", &n);
        init();
        int u, v;
        long long ww;
        for (int i = 0; i < n - 1; i++) {
            scanf("%d%d%lld", &u, &v, &ww);
            g[u].push_back(v);      
            g[v].push_back(u);      
            w[u].push_back(ww);
            w[v].push_back(ww);
        }
        scanf("%d", &m);
        for (int i = 0; i < m; i++) {
            scanf("%d%lld", &u, &ww);
            num[u] = ww;
        }
        memset(vis, 0, sizeof(vis));
        dfs(1);
        res = f[1];
        memset(vis, 0, sizeof(vis));
        dp(1);
        printf("%lld\n", res);
        int flag = 0;
        for (int i = 1; i <= n; i++) {
            if (f[i] == res && !flag) {
                printf("%d", i);
                flag = 1;
            }
            else if (f[i] == res)
                printf(" %d", i);
        }
        printf("\n");
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

uva 12223(树形dp)

标签:

原文地址:http://blog.csdn.net/hyczms/article/details/47009489

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!