很基础的一类题目,要用到01背包问题的思想。
ZOJ3201
题解
- 含有k个结点的权值和最大的子树。
- dp[i][j]表示以i为根的,含有j个结点的最大权值
- dp[i][j] = max(dp[i][j],dp[i][j-k] + dp[v][k])。v是i的子结点。类似于分组背包问题,每个结点算一个组,每个组又有很多种选择。
代码
#include <bits/stdc++.h>
using namespace std;
int const N = 100 + 10;
int n,k,dp[N][N],sz[N],ans;
vector<int>G[N];
void dfs(int u,int fa){
sz[u] = 1;
for(int i=0;i<G[u].size();i++){
int v = G[u][i];
if(v == fa) continue;
dfs(v,u);
sz[u] += sz[v];
}
for(int i=0;i<G[u].size();i++){
int v = G[u][i];
if(v == fa) continue;
for(int j=sz[u];j>=1;j--){
for(int k=1;k<j;k++)
dp[u][j] = max(dp[u][j],dp[u][j-k] + dp[v][k]);
}
}
}
int main(){
while(~scanf("%d%d",&n,&k)){
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++)
scanf("%d",&dp[i][1]); //直接初始化
for(int i=0;i<n;i++) G[i].clear();
for(int i=0;i<n-1;i++){
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(0,-1);
int ans = 0;
for(int i=0;i<n;i++) //遍历每一个点,考虑最大值
ans = max(ans,dp[i][k]);
printf("%d\n",ans);
}
return 0;
}
ural1018
题解
- 以1为根保留的q条边的最优值
- 相当于保留q+1个结点。
- 和上面一毛一样。只不过这里是边有权值,上边是点有权值
代码
#include <bits/stdc++.h>
using namespace std;
int const N = 100 + 10;
int n,q,dp[N][N],sz[N];
struct Node
{
int to,val;
Node(){}
Node(int to,int val):to(to),val(val){}
};
vector<Node>G[N];
void dfs(int u,int fa){
sz[u] = 1;
for(int i=0;i<G[u].size();i++){
Node e = G[u][i];
if(e.to == fa) continue;
dfs(e.to,u);
sz[u] += sz[e.to]; //sz表示以u为根的数的大小(包括根节点)
}
for(int i=0;i<G[u].size();i++){
Node e = G[u][i];
if(e.to == fa) continue;
for(int j=sz[u];j>1;j--){ //枚举子树的大小,要有根必须有两个结点
for(int k=1;k<j;k++){
dp[u][j] = max(dp[u][j],dp[u][j-k] + dp[e.to][k] + e.val);
}
}
}
}
int main(){
scanf("%d%d",&n,&q);
for(int i=0;i<n-1;i++){ //二叉树
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
G[u].push_back(Node(v,c));
G[v].push_back(Node(u,c));
}
dfs(1,-1);
printf("%d\n",dp[1][q+1]);
return 0;
}
HDU1561
题解
代码
#include <bits/stdc++.h>
using namespace std;
int const N = 200 + 10;
int n,m,dp[N][N],sz[N];
vector<int>G[N];
void dfs(int u,int fa){
sz[u] = 1;
for(int i=0;i<G[u].size();i++){
int v = G[u][i];
if(v == fa) continue;
dfs(v,u);
sz[u] += sz[v];
}
for(int i=0;i<G[u].size();i++){
int v = G[u][i];
if(v == fa) continue;
for(int j=sz[u];j>=1;j--){
for(int k=1;k<j;k++)
dp[u][j] = max(dp[u][j],dp[u][j-k] + dp[v][k]);
}
}
}
int main(){
while(~scanf("%d%d",&n,&m) && (n || m)){
for(int i=0;i<=n;i++) G[i].clear(), sz[i] = 0;
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++){
int a,b;
scanf("%d%d",&a,&dp[i][1]);
G[a].push_back(i);
}
dfs(0,-1);
printf("%d\n",dp[0][m+1]);
}
return 0;
}