poj 2152 Fire

原题链接:http://poj.org/problem?id=2152

一道我觉得很难的树形dp,想了很久都想不出状态转移方程式,搜了题解之后也看了很久。

思路: 用dp[u][i]表示以u为根的子树满足条件,并且结点u依赖于结点i的最小花费。

      用best[u]表示以u根的子树满足条件的最小花费,那么best[u]=min(dp[u][i])。

      求best[u]时,先跑一遍dfs得到所有结点距离u的距离dis[i]。如果dis[i]>d[u],那么u没法依赖i,此时dp[u][i]=inf。否则dis[i]<=d[u],此时dp[u][i]=w[i]+sum( min( best[v] , dp[v][i]-w[i] ) ),其中i从1遍历到n,v是u的子结点。因为v的依赖有两种情况,如果v依赖于以v为根的子树中的结点,即best[v]; 如果v依赖于其余的结点,那么一定是i。反证一下,如果v依赖于k,那么u也一定依赖于k。所以应取best[v]和dp[v][i]-w[i]的最小值,减w[i]是因为w[i]多加了一次。

#include <stdio.h>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <map> 
#include <stack>
#include <sstream>
#include <set>
#pragma GCC optimize(2)

//#define int long long
#define mm(i,v) memset(i,v,sizeof i);
#define mp(a, b) make_pair(a, b)
#define pi acos(-1)
#define fi first
#define se second
//你冷静一点,确认思路再敲!!! 

using namespace std;
typedef long long ll;
typedef pair<int, int > PII;
priority_queue< PII, vector<PII>, greater<PII> > que;
stringstream ssin; //  ssin << string   while ( ssin >> int)

const int N = 2e3 + 5, mod = 1e9 + 9, INF = 0x3f3f3f3f;
int T, n, m, cnt, wei[N], d[N], dp[N][N], dis[N], idx;
int e[N], h[N], ne[N], w[N], best[N];

inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
    return x*f;
}

void add(int a, int b, int c) {
    e[idx] = b;
    w[idx] = c;
    ne[idx] = h[a];
    h[a] = idx++;
}

void init() {
    mm(h, -1);
    idx = 0;
    cnt = 0;
}

void getdis(int u, int fa, int len) {
    dis[u] = len;
    for (int i = h[u]; ~i; i = ne[i]) {
        int v = e[i], z = w[i];
        if (v == fa) continue;
        getdis(v, u, len + z);
    }
}

void dfs(int u, int fa) {
    for (int i = h[u]; ~i; i = ne[i]) {
        int v = e[i];
        if (v == fa) continue;
        dfs(v, u);
    }
    getdis(u, -1, 0);
    best[u] = INF;
    for (int i = 1; i <= n; ++i) {
        if (dis[i] > d[u]) dp[u][i] = INF;
        else {
            dp[u][i] = wei[i];
            for (int j = h[u]; ~j; j = ne[j]) {
                int v = e[j];
                if (v == fa) continue;
                dp[u][i] += min(best[v], dp[v][i] - wei[i]);
            }
        }
        best[u] = min(best[u], dp[u][i]);
    }
}

int main()
{
    cin >> T;
    while (T--) {
        init();
        cin >> n;
        for (int i = 1; i <= n; ++i) wei[i] = read();
        for (int i = 1; i <= n; ++i) d[i] = read();
        for (int i = 1; i < n; ++i) {
            int a, b, c;
            a = read(); b = read(); c = read();
            add(a, b, c);
            add(b, a, c);
        }
        dfs(1, -1);
        cout << best[1] << endl;
    }
    // system("pause");
    return 0;
}
View Code

 

posted @ 2020-07-07 20:43  violet72  阅读(83)  评论(0编辑  收藏  举报