树形DP模型

285. 没有上司的舞会

https://www.acwing.com/problem/content/287/

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#include<unordered_map>
using namespace std;
typedef long long LL;
const int N=6010;
int f[N][2];//f(i,0) 不选择i f(i,1)选择i
int happy[N];
int h[N],e[N],ne[N],idx;
bool is_children[N];
int n;
void add(int a,int b){
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}
void dfs(int u){
    f[u][1]=happy[u];
    for(int i=h[u];i!=-1;i=ne[i]){
        int j=e[i];
        dfs(j);
        f[u][0]+=max(f[j][0],f[j][1]);
        f[u][1]+=f[j][0];
    }
}
int main(){
    memset(h,-1,sizeof h);
    cin>>n;
    for(int i=1;i<=n;i++) cin>>happy[i];
    for(int i=1;i<n;i++){
        int a,b;
        cin>>a>>b;
        add(b,a);
        is_children[a]=true;
    }
    int root=1;
    while(is_children[root]) root++;
    dfs(root);
    cout<<max(f[root][0],f[root][1])<<endl;
  return 0;
}
//  freopen("testdata.in", "r", stdin);

1072. 树的最长路径

https://www.acwing.com/problem/content/1074/

树的直径写法

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#include<unordered_map>
using namespace std;
typedef long long LL;
const int N=2e5+10;
int h[N],w[N],ne[N],e[N],idx;
int dist[N];
int n;
void add(int a,int b,int c){
    e[idx]=b;
    w[idx]=c;
    ne[idx]=h[a];
    h[a]=idx++;
}
void dfs(int u,int father,int distance){
    dist[u]=distance;
    for(int i=h[u];i!=-1;i=ne[i]){
        int j=e[i];
        if(j!=father){
            dfs(j,u,distance+w[i]);
        }
    }
}
int main(){
    cin>>n;
    memset(h,-1,sizeof h);
    for(int i=0;i<n-1;i++){
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
        add(b,a,c);
    }
    dfs(1,-1,0);
    int u=1;
    for(int i=1;i<=n;i++){
        if(dist[i]>dist[u]) u=i;
    }
    dfs(u,-1,0);
    for(int i=1;i<=n;i++){
        if(dist[i]>dist[u]) u=i;
    }
    int s=dist[u];
    cout<<s<<endl;
  return 0;
}
//  freopen("testdata.in", "r", stdin);

树形DP写法

树形dp,实际上就是两次dfs,
从一个点出发找一条最长边,和一条次长边

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#include<unordered_map>
using namespace std;
typedef long long LL;
const int N=2e5+10;
int h[N],w[N],e[N],ne[N],idx;
void add(int a,int b,int c){
    e[idx]=b;
    w[idx]=c;
    ne[idx]=h[a];
    h[a]=idx++;
}
int ans=0;
int n;
int dfs(int u,int father){
    int dist=0;//表示从u出发向下走的最大长度
    int d1=0;//最大长度
    int d2=0;//次大长度
    for(int i=h[u];i!=-1;i=ne[i]){
        int j=e[i];
        if(j==father) continue;
        int d=dfs(j,u)+w[i];
        dist=max(dist,d);
        if(d>=d1){
            d2=d1;
            d1=d;
        }
        else if(d>d2){
            d2=d;
        }
        ans=max(ans,d1+d2);
    }
    return dist;
}
int main(){
    cin>>n;
    memset(h,-1,sizeof h);
    for(int i=0;i<n-1;i++){
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
        add(b,a,c);
    }
    dfs(1,-1);
    cout<<ans<<endl;
  return 0;
}
//  freopen("testdata.in", "r", stdin);

1073. 树的中心

https://www.acwing.com/problem/content/description/1075/

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#include<unordered_map>
using namespace std;
typedef long long LL;
const int N=2e5+10,INF=0x3f3f3f3f;
int h[N],ne[N],e[N],w[N],idx;
int n;
int d1[N],d2[N],up[N],p1[N];
bool is_leaf[N];
void add(int a,int b,int c){
    e[idx]=b;
    w[idx]=c;
    ne[idx]=h[a];
    h[a]=idx++;
}
int dfsdown(int u,int father){
    d1[u]=d2[u]=-INF;
    for(int i=h[u];i!=-1;i=ne[i]){
        int j=e[i];
        if(j==father) continue;
        int d=dfsdown(j,u)+w[i];
        if(d>=d1[u]){
            d2[u]=d1[u];
            d1[u]=d;
            p1[u]=j;//进行保存,表面u-j是从u走的最大路径
        }
        else if(d>d2[u]) d2[u]=d;
    }
    if(d1[u]==-INF){
        d1[u]=d2[u]=0;
        //说明无法向下走 是叶子
        is_leaf[u]=true;
    }
    return d1[u];
}
void dfsup(int u,int father){
    for(int i=h[u];i!=-1;i=ne[i]){
        int j=e[i];
        if(j==father) continue;
        if(p1[u]==j){//说明u-j就是最大路径,所以必须选择次大路径才能避免重复走
            up[j]=max(up[u],d2[u])+w[i];
        }
        else up[j]=max(up[u],d1[u])+w[i];
        dfsup(j,u);
    }
}
int main(){
    cin>>n;
    memset(h,-1,sizeof h);
    for(int i=0;i<n-1;i++){
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
        add(b,a,c);
    }
    dfsdown(1,-1);
    dfsup(1,-1);
    int res=d1[1];
    for (int i = 2; i <= n; i ++ )
        if (is_leaf[i]) res = min(res, up[i]);
        else res = min(res, max(d1[i], up[i]));
    printf("%d\n", res);
  return 0;
}
//  freopen("testdata.in", "r", stdin);

1075. 数字转换

https://www.acwing.com/problem/content/description/1077/
一:求2 到 n 中每一个数的因数和,1不算是因为题意

 for(int i = 1;i <= n;++i)//i是因数
        for(int j = 2;j <= n/i;++j)//j代表i的放大倍数
            sum[i*j] += i;

#include <bits/stdc++.h>
using namespace std;

const int N = 50010, M = N * 2;

int h[N], w[M], ne[M], v[M], idx;
int sum[N];
int n;
int ans;

void add(int a, int b, int c){
    ++idx;w[idx] = c;v[idx] = b;ne[idx] = h[a];h[a] = idx;
}

int dfs(int u){
    int d1 = 0, d2 = 0;
    for(int i = h[u];i;i = ne[i]){
        int k = v[i];
        int d = dfs(k) + w[i];
        if(d >= d1) d2 = d1, d1 = d;
        else if(d > d2) d2 = d;
    }
    ans = max(ans, d1 + d2);
    return d1;
}

int main(){
    cin >> n;
    for(int i = 1;i <= n;++i)
        for(int j = 2;j <= n/i;++j)
            sum[i*j] += i;

    for(int i = 2;i <= n;++i)
        if(sum[i] < i)
            add(sum[i], i, 1);

    dfs(1);

    cout << ans << endl;
    return 0;
}

1220. 生命之树

https://www.acwing.com/problem/content/1222/

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#include<unordered_map>
using namespace std;
typedef long long LL;
const int N=2e6+10;
int h[N],e[N],ne[N],w[N],idx;
int n;
LL f[N];
void add(int a,int b){
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}
LL dfs(int u,int father){
    f[u]=w[u];
    for(int i=h[u];i!=-1;i=ne[i]){
        int j=e[i];
        if(j==father) continue;
        f[u]=max(f[u],f[u]+dfs(j,u));
    }
    return f[u];
}
int main(){
    memset(h,-1,sizeof h);
    cin>>n;
    for(int i=1;i<=n;i++) cin>>w[i];
    for(int i=0;i<n-1;i++){
        int a,b;
        cin>>a>>b;
        add(a,b);
        add(b,a);
    }
    dfs(1,-1);
    LL res=f[1];
    for(int i=2;i<=n;i++){
        res=max(res,f[i]);
    }
    cout<<res<<endl;
  return 0;
}
//  freopen("testdata.in", "r", stdin);

1078. 旅游规划

https://www.acwing.com/problem/content/1080/

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#include<unordered_map>
using namespace std;
typedef long long LL;
const int N=2e5+10,M=2*N;
int h[N],e[M],ne[M],idx;
int d1[N],d2[N],up[N],p[N];
int n,len=0;
void add(int a,int b){
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}
void dfs_down(int u,int father){
    for(int i=h[u];i!=-1;i=ne[i]){
        int j=e[i];
        if(j==father) continue;
        dfs_down(j,u);
        int d=d1[j]+1;
        if(d>=d1[u]){
            p[u]=j;
            d2[u]=d1[u];
            d1[u]=d;
        }
        else if(d>d2[u]){
            d2[u]=d;
        }
    }
    len=max(len,d1[u]+d2[u]);
}
void dfs_up(int u,int father){
    for(int i=h[u];i!=-1;i=ne[i]){
        int j=e[i];
        if(j==father) continue;
        up[j] = up[u] + 1;//算出从j到u继续往上走的值
        if(p[u]==j) up[j]=max(up[j],1+d2[u]);//和往下走的值进行比较
        else up[j]=max(up[j],1+d1[u]);
        dfs_up(j,u);
    }
}
int main(){
    cin>>n;
    memset(h,-1,sizeof h);
    for (int i = 0; i < n-1; i ++ ){
        int a,b;
        cin>>a>>b;
        add(a,b);
        add(b,a);
    }
    dfs_down(0,-1);
    dfs_up(0,-1);
    for (int i = 0; i < n; i ++ )
    {
        int d[3] = {d1[i], d2[i], up[i]};
        sort(d, d + 3);
        if (d[1] + d[2] == len) printf("%d\n", i);
    }

  return 0;
}
//  freopen("testdata.in", "r", stdin);
posted @ 2021-05-20 10:00  一个经常掉线的人  阅读(58)  评论(0)    收藏  举报