目录
刷题记录
ZJNU树形dp - Virtual Judge (vjudge.net)
解析
树形dp一般形式就两种:
dp[根节点][0/1状态]
dp[根节点][从子树拿了多少节点]
没有上司的舞会
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
#define pii pair<int,int>
#define rep(i,l,r) for (int i=l;i<=r;i++)
#define nep(i,r,l) for (int i=r;i>=l;i--)
#define CIO std::ios::sync_with_stdio(false)
using namespace std;
const int N=2e5+5;
int val[N];
int dp[N][2];
int v[N];
vector<int> ve[N];
void dfs(int x,int fa){
dp[x][0]=0;
dp[x][1]=val[x];
for (int i=0;i<ve[x].size();i++){
dfs(ve[x][i],x);
int v=ve[x][i];
dp[x][0]+=max(dp[v][1],dp[v][0]);
dp[x][1]+=dp[v][0];
}
}
void work(){
int n;
cin>>n;
rep(i,1,n){
cin>>val[i];
}
int x,fa;
rep(i,1,n-1){
cin>>x>>fa;
ve[fa].push_back(x);
v[x]=1;
}
int root,ans=0;
rep(i,1,n){
if (v[i]==0){
root=i;
}
}
dfs(root,0);
cout<<max(dp[root][0],dp[root][1])<<endl;
}
signed main(){
CIO;
//int _;cin>>_;while(_--)
{
work();
}
return 0;
}
有线电视网
树上背包问题
1是根节点,2到n-m是中继器,n-m+1到n是终端。终端有各自的钱,树上边权会消耗钱
,问从根节点能到多少个终端使得钱不亏本。
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
#define pii pair<int,int>
#define pb push_back
#define rep(i,l,r) for (int i=l;i<=r;i++)
#define nep(i,r,l) for (int i=r;i>=l;i--)
#define CIO std::ios::sync_with_stdio(false)
using namespace std;
const int N=3e3+5;
int dp[N][N];
struct edge{
int to,w;
};
int siz[N];
vector<edge> ve[N];
void dfs(int x,int fa){
if (ve[x].size()==0){
siz[x]=1;
}
for (int i=0;i<ve[x].size();i++){
int v=ve[x][i].to,w=ve[x][i].w;
if (v!=fa){
dfs(v,x);
siz[x]+=siz[v];
for (int j=siz[x];j>=1;j--){
for (int k=1;k<=siz[x];k++){
dp[x][j]=max(dp[x][j],dp[x][j-k]+dp[v][k]-w);
}
}
}
}
}
void work(){
int n,m;cin>>n>>m;
rep(i,1,n-m){
int k;cin>>k;
int v,w;
rep(j,1,k){
cin>>v>>w;
ve[i].push_back({v,w});
}
}
rep(i,1,n){
rep(j,1,n){
dp[i][j]=-21000000;
}
}
rep(i,n-m+1,n){
cin>>dp[i][1];
}
dfs(1,-1);
nep(i,m,1){
if (dp[1][i]>=0){
cout<<i<<endl;
return;
}
}
}
signed main(){
CIO;
{
work();
}
return 0;
}
树形dp换根(二次扫描)
给定一个 n 个点的树,请求出一个结点,使得以这个结点为根时,所有结点的深度之和
最大。一个结点的深度之定义为该节点到根的简单路径上边的数量。
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
#define pii pair<int,int>
#define pb push_back
#define rep(i,l,r) for (int i=l;i<=r;i++)
#define nep(i,r,l) for (int i=r;i>=l;i--)
#define CIO std::ios::sync_with_stdio(false)
using namespace std;
const int N=1e6+5;
const int inf=2100000000;
struct edge{
int to,w;
};
int siz[N],dep[N];
int f[N];
int n;
vector<int> ve[N];
void dfs(int x,int fa){
siz[x]=1;
dep[x]=dep[fa]+1;
for (int i=0;i<ve[x].size();i++){
int v=ve[x][i];
if (v!=fa){
dfs(v,x);
siz[x]+=siz[v];
}
}
}
void dfsroot(int x,int fa){//从根往下传递
for (int i=0;i<ve[x].size();i++){
int v=ve[x][i];
if (v!=fa){
f[v]=f[x]+n-2*siz[v];
dfsroot(v,x);
}
}
}
void work(){
cin>>n;
int u,v;
rep(i,1,n-1){
cin>>u>>v;
ve[u].push_back(v);
ve[v].push_back(u);
}
dep[0]=-1;
dfs(1,0);
rep(i,1,n) f[1]+=dep[i];
dfsroot(1,0);
int maxdep=-1,maxroot;
rep(i,1,n){
if (maxdep<f[i]){
maxroot=i;
maxdep=f[i];
}
}
cout<<maxroot<<endl;
}
signed main(){
CIO;
{
work();
}
return 0;
}