您的位置:首页 > 其它

POJ 1155 TELE (树状DP)

2014-08-02 00:39 288 查看
题目类型 树状DP

题目意思
给出 n 个点 (2 <= n <= 3000) 和 一个数 m (m 表示 n 个点中有多少个叶子结点)
然后给出每一个非叶子结点与其他点相连的边 这些点和边构成一棵树
非叶子结点与叶子结点之间的边在计算时是加的 而非叶子结点之间的边在计算时是减的
现在问从根 1 可以到达最多多少个叶子结点 (要求根到这些叶子结点的路径权值加起来非负, 相同的边只计算一次)

解题方法

树状DP

dp[i][j] -> 表示以 i 结点为根去到 j 个叶子结点的路径权值和加起来最大是多少

那么用子结点 v 去优化父结点 u 的转移方程如下

dp[u][j] = max(dp[u][j], dp[u][j-k] + dp[v][k] - W[u][v]); 其中 (1<=j<=子树u拥有的叶子结点数) (1<=k<=子树v拥有的叶子结点数)

即像01背包那样用以子结点为根的子树的一部分去更新父结点 这里要考虑重复使用一部分去更新的情况 详细见代码

参考代码 - 有疑问的地方在下方留言 看到会尽快回复的

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>

using namespace std;

const int INF = 1<<29;

int dp[3010][3010];
int num[3010];
vector<int>M[3010];
vector<int>W[3010];
int in[3010], n, m;
int tmp[3010];

void DFS(int u, int fa) {
if(u > n-m) { // 如果结点 u 是叶子结点的话 直接把与u相连的边的权值赋给 dp[u][1]
dp[u][1] = in[u];
return ;
}
for( int i=0; i<M[u].size(); i++ ) { // 枚举 u 的子结点
int v = M[u][i];
if(v == fa) continue;
DFS(v, u);
for( int j=1; j<=num[u]; j++ ) tmp[j] = dp[u][j]; // 先保存结点 u 的数据 避免某一部分重复更新
for( int j=1; j<=num[v]; j++ ) { // 相当于01背包中的 num[v]件物品 每件物品的体积是 j 价值是 dp[v][j]
for( int k=num[u]; k>=j; k-- ) {
dp[u][k] = max(dp[u][k], tmp[k-j]+dp[v][j] - W[u][i]); // 如果不使用 tmp数组的话 子结点v的某一比较优的部分会重复使用
}
}
}
}

void Init(int u, int fa) { // 求以 u 为根的子树包含的叶子结点数
if(u > n-m) {
num[u] = 1;
return ;
}
num[u] = 0;
for( int i=0; i<M[u].size(); i++ ) {
int v = M[u][i];
if(v == fa) continue;
Init(v, u);
num[u] += num[v];
}
}

int main() {
freopen("in", "r", stdin);
while(scanf("%d%d", &n, &m) != EOF) {
for( int i=1; i<=n; i++ ) for( int j=0; j<=n; j++ ) dp[i][j] = -INF;
for( int i=1; i<=n; i++ ) dp[i][0] = 0;
for( int i=1; i<=n-m; i++ ) M[i].clear(), W[i].clear();
for( int i=1; i<=n-m; i++ ) {
int k;
scanf("%d", &k);
for( int j=0; j<k; j++ ) {
int v, w;
scanf("%d%d", &v, &w);
M[i].push_back(v);
W[i].push_back(w);
}
}
for( int i=n-m+1; i<=n; i++ ) scanf("%d", &in[i]);
Init(1, 0);
DFS(1, 0);
int ans = 0;
for( int i=m; i>=0; i-- ) if(dp[1][i] >= 0) { ans = i; break; }
printf("%d\n", ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: