acwing题高树型DP

树的最长路径

![在这里插入图片描述]( https://img-blog.csdnimg.cn/458e03be334b4c8483a81b547d5e1740.png?x-oss-process=image/watermark ,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGFuc2XCtw==,size_20,color_FFFFFF,t_70,g_se,x_16)

样例输入:

6
5 1 6
1 4 5
6 3 9
2 6 8
6 1 7

样例输出:

22

代码模板:

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

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

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

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

int dfs(int u, int father)
{
    int dist = 0; // 表示从当前点往下走的最大长度
    int d1 = 0, 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;
}

 

树的中心

![在这里插入图片描述]( https://img-blog.csdnimg.cn/5cc578ca76944047b42bdbf92720ad6e.png?x-oss-process=image/watermark ,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGFuc2XCtw,size_20,color_FFFFFF,t_70,g_se,x_16)
思路
例:
![在这里插入图片描述]( https://img-blog.csdnimg.cn/96d549615a8e4001a744eae634e023ed.png?x-oss-process=image/watermark ,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGFuc2XCtw
,size_20,color_FFFFFF,t_70,g_se,x_16)

样例输入:

5 
2 1 1 
3 2 1 
4 3 1 
5 1 1

样例输出:

2

代码模板:

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 10010, M = N * 2, INF = 0x3f3f3f3f;

int n;
int h[N], e[M], w[M], ne[M], idx;
int d1[N], d2[N], p1[N], up[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 dfs_d(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 = dfs_d(j, u) + w[i];
        if (d >= d1[u])
        {
            d2[u] = d1[u], d1[u] = d;
            p1[u] = j;
        }
        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 dfs_u(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) up[j] = max(up[u], d2[u]) + w[i]; 当前节点是u节点最长的边
        else up[j] = max(up[u], d1[u]) + w[i];当前节点不是u节点最长的边

        dfs_u(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);
    }

    dfs_d(1, -1);
    dfs_u(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;
}

 

数字转换

![在这里插入图片描述]( https://img-blog.csdnimg.cn/d2446500ddca4204aa7002427e17bddb.png?x-oss-process=image/watermark ,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGFuc2XCtw==,size_20,color_FFFFFF,t_70,g_se,x_16)

样例输入:

7

样例输出:

3

代码模板:

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 50010, M = N;

int n;
int h[N], e[M], w[M], ne[M], idx;
int sum[N];
bool st[N];
int ans;

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

//树的最长直径
int dfs(int u)
{
    st[u] = true;

    int dist = 0;
    int d1 = 0, d2 = 0;
    for (int i = h[u]; ~i; i = ne[i])
    {
       int j = e[i];
       if (!st[j])
       {
           int d = dfs(j);
           dist = max(dist, d);
           if (d >= d1) d2 = d1, d1 = d;
           else if (d > d2) d2 = d;
       }
    }

    ans = max(ans, d1 + d2);

    return dist + 1;
}

int main()
{
    cin >> n;
    memset(h, -1, sizeof h);

    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);

    for (int i = 1; i <= n; i ++ )
        dfs(i);

    cout << ans << endl;

    return 0;
}

 

二叉苹果树

![在这里插入图片描述]( https://img-blog.csdnimg.cn/b84c0d743bdd4716bd0a698576eb1daa.png?x-oss-process=image/watermark ,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGFuc2XCtw==,size_20,color_FFFFFF,t_70,g_se,x_16)
样例输入:

5 2
1 3 1
1 4 10
2 3 20
3 5 20

样例输出:

21

代码模板:

//有依赖的背包问题简化
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

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

int n, m;
int h[N], e[M], w[M], ne[M], idx;
int f[N][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)
{
//分组背包
    for (int i = h[u]; ~i; i = ne[i]) //物品
    {
        if (e[i] == father) continue;
        dfs(e[i], u);
      
        for (int j = m; j; j -- )  //体积
            for (int k = 0; k + 1 <= j; k ++ ) //决策
                f[u][j] = max(f[u][j], f[u][j - k - 1] + f[e[i]][k] + w[i]);
    }
}

int main()
{
    cin >> n >> m;
    memset(h, -1, sizeof h);
    for (int i = 0; i < n - 1; i ++ )
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        add(a, b, c), add(b, a, c);
    }

    dfs(1, -1);

    printf("%d\n", f[1][m]);

    return 0;
}

 

战略游戏

![在这里插入图片描述]( https://img-blog.csdnimg.cn/58d713df4a4142aeb3c2d224a9f69658.png?x-oss-process=image/watermark ,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGFuc2XCtw==,size_20,color_FFFFFF,t_70,g_se,x_16)

样例输入:

4
0:(1) 1
1:(2) 2 3
2:(0)
3:(0)
5
3:(3) 1 4 2
1:(1) 0
2:(0)
0:(0)
4:(0)

样例输出:

1
2

代码模板:

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1510;

int n;
int h[N], e[N], ne[N], idx;
int f[N][2];
bool st[N];

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

void dfs(int u)
{
    f[u][0] = 0, f[u][1] = 1;
    for (int i = h[u]; ~i; i = ne[i])
    {
        int j = e[i];
        dfs(j);
        f[u][0] += f[j][1];
        f[u][1] += min(f[j][0], f[j][1]);
    }
}

int main()
{
    while (cin >> n)
    {
        memset(h, -1, sizeof h);
        idx = 0;

        memset(st, 0, sizeof st);
        for (int i = 0; i < n; i ++ )
        {
            int id, cnt;
            scanf("%d:(%d)", &id, &cnt);
            while (cnt -- )
            {
                int ver;
                cin >> ver;
                add(id, ver);
                st[ver] = true;
            }
        }

        int root = 0;
        while (st[root]) root ++ ;
        dfs(root);

        printf("%d\n", min(f[root][0], f[root][1]));
    }

    return 0;
}

 

皇宫看守

![在这里插入图片描述]( https://img-blog.csdnimg.cn/c70e22e0fb304af58e98adceaf1ed16b.png?x-oss-process=image/watermark ,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGFuc2XCtw==,size_20,color_FFFFFF,t_70,g_se,x_16)
样例输入:

6
1 30 3 2 3 4
2 16 2 5 6
3 5 0
4 4 0
5 11 0
6 5 0

样例输出:

25

代码模板:

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1510;

int n;
int h[N], w[N], e[N], ne[N], idx;
int f[N][3]; //0被父节点看到 1被子节点看到 2摆放警卫 
bool st[N];

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

void dfs(int u)
{
    f[u][2] = w[u];

    int sum = 0;
    for (int i = h[u]; ~i; i = ne[i])
    {
        int j = e[i];
        dfs(j);
        f[u][0] += min(f[j][1], f[j][2]);
        f[u][2] += min(min(f[j][0], f[j][1]), f[j][2]);
        sum += min(f[j][1], f[j][2]);
    }

    f[u][1] = 1e9;
    for (int i = h[u]; ~i; i = ne[i])//只要被其中一个子节点看到 
    {
        int j = e[i];
        f[u][1] = min(f[u][1], sum - min(f[j][1], f[j][2]) + f[j][2]);
    }
}

int main()
{
    cin >> n;

    memset(h, -1, sizeof h);
    for (int i = 1; i <= n; i ++ )
    {
        int id, cost, cnt;
        cin >> id >> cost >> cnt;
        w[id] = cost;
        while (cnt -- )
        {
            int ver;
            cin >> ver;
            add(id, ver);
            st[ver] = true;
        }
    }

    int root = 1;
    while (st[root]) root ++ ;

    dfs(root);

    cout << min(f[root][1], f[root][2]) << endl;

    return 0;
}

 

posted @ 2022-03-22 14:39  panse·  阅读(41)  评论(0)    收藏  举报