luogu 1352 没有上司的舞会
地址:https://www.luogu.com.cn/problem/P1352
题解:f[i][0]表示这个点不取的情况下的最优解,那它下面的点是可选可不选的状态,所以它的转移为sum(max(f[j][0],f[j][1])),f[i][1]表示这个点是取的状态,那么它下面一层是不能选的,转移方程为sum(f[j][0])+a[i]
#include
using namespace std;
struct edge{
int n,o;
}e[15000];
int last[7000],flag[7000],f[7000][2];
int w,n,a[7000],x,y,root,ru[7000];
void add(int x,int y){
w++;e[w].n=last[x];last[x]=w;e[w].o=y;
}
void dfs(int now){
flag[now]=1;
f[now][0]=0;
f[now][1]=a[now];
for(int w1=last[now];w1;w1=e[w1].n){
int y=e[w1].o;
if(flag[y]==1)continue;
dfs(y);
f[now][0]+=max(f[y][0],f[y][1]);
f[now][1]+=f[y][0];
}
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<n;i++){
cin>>x>>y;
add(y,x);
ru[x]++;
}
for(int i=1;i<=n;i++)
if(ru[i]==0)root=i;
dfs(root);
cout<<max(f[root][0],f[root][1])<<endl;
return 0;
}
luogu 5536 【XR-3】核心城市
地址:https://www.luogu.com.cn/problem/P5536
题解:从最外面的叶子节点开始,一层层往里去除,直到最后剩下的节点数量为k。
注意去掉的时候要有层次感,一个点去掉的前提是它外围的所有枝条都去除了,不然提前去除会有出错的数据。
#include
using namespace std;
#define N 110000
struct edge{
int n,o;
}e[210000];
queue<int>q;
int w,last[N],n,m,flag[N],x,y,ru[N],flag1[N],ans,mark;
void add(int x,int y){
w++;e[w].n=last[x];last[x]=w;e[w].o=y;
}
void dfs(int now,int dist){
flag1[now]=2;
ans=max(ans,dist);
for(int w1=last[now];w1;w1=e[w1].n){
int y=e[w1].o;
if(flag1[y]==2)continue;
if(flag1[y]==1)dfs(y,dist+1);
else dfs(y,0);
}
}
int main(){
cin>>n>>m;
for(int i=1;i<n;i++){
cin>>x>>y;
add(x,y);
add(y,x);
ru[x]++;
ru[y]++;
}
for(int i=1;i<=n;i++)
if(ru[i]==1)q.push(i),flag[i]=1;
m=n-m;
if(m==0){
cout<<0<<endl;
return 0;
}
for(int i=1;i<=m;i++){
x=q.front();
flag1[x]=1;
q.pop();
for(int w1=last[x];w1;w1=e[w1].n){
y=e[w1].o;
if(flag[y]==1)continue;
ru[y]--;
if(ru[y]==1){
flag[y]=1;
q.push(y);
}
}
}
for(int i=1;i<=n;i++)
if(flag1[i]==0)mark=i;
dfs(mark,0);
cout<<ans<<endl;
return 0;
}
luogu 2014 [CTSC1997]选课
地址:https://www.luogu.com.cn/problem/P2014
题解:树形dp+背包dp
为了方便处理,将0号结果作为最终的root节点,同时我们选取的数量变为m+1个。
对于每个节点,当处理完它所有儿子节点时,就可以根据它的所有儿子节点对此父亲节点做背包dp。
#include
using namespace std;
struct edge{
int n,o;
}e[700];
int x,y,n,m,w;
int f[310][310],last[310];
void add(int x,int y){
w++;e[w].n=last[x];last[x]=w;e[w].o=y;
}
void dp(int now){
for(int w1=last[now];w1;w1=e[w1].n){
int y=e[w1].o;
dp(y);
for(int i=m+1;i>=1;i--)
for(int j=1;j<=i;j++)
f[now][i]=max(f[now][i],f[now][i-j]+f[y][j]);
}
}
int main(){
cin>>n>>m;
memset(f,-42,sizeof(f));
for(int i=1;i<=n;i++){
cin>>x>>y;
add(x,i);
f[i][1]=y;
}
f[0][1]=0;
dp(0);
cout<<f[0][m+1]<<endl;
return 0;
}