zoukankan      html  css  js  c++  java
  • POJ-1947 Rebuilding Roads

    题目给出一棵树,求切出一棵节点数为p的新树最少要切多少条边。

    比较明显的树形DP,dp[i][j]为第i个节点为根的子树具有j个节点最少要切的边数。

    初始化的时候不应该考虑子树需要切断与父亲的边才能成树这一情况,因为dp在转移的时候是把子树当成与当前节点连接着来考虑的,这样写起来更加方便。最后更新ans的时候再考虑是不是子树就好。

    考虑一个节点,有dp[now][0]=0。对于它的子树,如果不要,则有dp[i][0]=dp[i][0]+1(因为不要,则数目不变,但耗费+1);如果要这颗子树,这里需要处理要多少的问题,即再开一层循环,dp[now][j]=min(*,dp[child][k]+dp[now][j-k])

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include <string>
    #include<queue>
    #include<vector>
    #include<set>
    #include<map>
    #define LL long long
    using namespace std;
    const int N = 160;
    const LL inf = 9999999;
    LL n, p;
    LL dp[N][N];
    LL cnt[N];
    vector<int> g[N];
    LL ans;
    int rt;
    void dfs(int now)
    {
        for (int i = 0; i < g[now].size(); i++)
        {
            int nx = g[now][i];
            dfs(nx);
            cnt[now] += cnt[nx];
        }
        fill(dp[now], dp[now] + N, inf);
        dp[now][1] = 0;
        for (int i = 0; i < g[now].size(); i++)
        {
            //LL temp[N];
            //fill(temp, temp + N, inf);
            int e = g[now][i];
            for (int j = p; j>=1; j--)
            {
                LL temp = dp[now][j]+1;
                for (int k = 1;k<j; k++)
                    temp = min(temp, dp[now][j - k] + dp[e][k]);
                dp[now][j] = temp;
            }
            //for (int j = 1; j <= cnt[now]; j++)
                //dp[now][j] = temp[j];
        }
        if(now==rt)
            ans = min(ans, dp[now][p]);
        else ans = min(ans, dp[now][p] + 1);
    }
    int  main()
    {
        while (cin >> n >> p)
        {
            ans = inf;
            bool vis[N];
            fill(vis, vis + N, true);
            for (int i = 0; i < N; i++) g[i].clear();
            for (int i = 0; i < n - 1; i++)
            {
                int x, y;
                cin >> x >> y;
                g[x].push_back(y);
                vis[y] = false;
            }
            for (int i = 1; i <= n; i++)if (vis[i]) rt = i;
            fill(cnt, cnt + N, 1);
            dfs(rt);
            cout << ans << endl;
        }
    
        return 0;
    }
  • 相关阅读:
    不得不爱开源 Wijmo jQuery 插件集(6)【Popup】(附页面展示和源码)
    遗漏的知识点
    初识函数
    ==和is的区别 以及编码和解码
    函数的动态参数 及函数嵌套
    基本数据类型补充、set集合、深浅拷贝
    文件操作
    基本数据类型之“字典”
    建立自己的Servlet
    还原误删数据笔记
  • 原文地址:https://www.cnblogs.com/LukeStepByStep/p/7326139.html
Copyright © 2011-2022 走看看