题目链接:
POJ 2152 Fire
题意:
给一个
n
个节点和
数据范围:
分析:
点依赖型树形
dp
。
首先对每个点
dfs
一遍可以得到每个点到其余点的距离,时间复杂度:
O(n2)
。
然后递归解决以
u
为根的子树, 需要记录或者说枚举
更新 best[] : best[u]=min(best[u],dp[u][i])
总的时间复杂度: O(n2) 。
陈启峰的”一张一弛,解题之道”论文
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;
typedef long long ll;
const int MAX_N = 1010;
const int inf = 0x3f3f3f3f;
int T, n, total;
int head[MAX_N], cost[MAX_N], limit[MAX_N], dis[MAX_N][MAX_N];
int dp[MAX_N][MAX_N], best[MAX_N];
struct Edge {
int v, w, next;
}edge[MAX_N * 2];
void AddEdge(int u, int v, int w)
{
edge[total].v = v;
edge[total].w = w;
edge[total].next = head[u];
head[u] = total++;
}
void dfs_dis(int u, int p, int root)
{
for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].v, w = edge[i].w;
if (v == p) continue;
dis[root][v] = dis[root][u] + w;
dfs_dis(v, u, root);
}
}
void wyr(int u, int p)
{
for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].v;
if (v == p) continue;
wyr(v, u);
}
for (int i = 1; i <= n; ++i) {
if (dis[u][i] > limit[u]) continue;
dp[u][i] = cost[i];
//printf("dp[%d][%d] = %d\n", u, i, dp[u][i]);
for (int j = head[u]; j != -1; j = edge[j].next) {
int v = edge[j].v, w = edge[j].w;
if (v == p) continue;
dp[u][i] += min(dp[v][i] - cost[i], best[v]);
}
best[u] = min(best[u], dp[u][i]);
//printf("i = %d best[%d] = %d dp[%d][%d] = %d\n", i, u, best[u], u, i, dp[u][i]);
}
}
int main()
{
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) { scanf("%d", &cost[i]); }
for (int i = 1; i <= n; ++i) { scanf("%d", &limit[i]); }
total = 0;
memset(head, -1, sizeof(head));
for (int i = 1; i < n; ++i) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
AddEdge(u, v, w);
AddEdge(v, u, w);
}
memset(dis, 0, sizeof(dis));
for (int i = 1; i <= n; ++i) { dfs_dis(i, -1, i); }
memset(best, 0x3f, sizeof(best));
memset(dp, 0x3f, sizeof(dp));
wyr(1, 0);
printf("%d\n", best[1]);
}
return 0;
}