• 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;
    }
  • 相关阅读:
    Java注释中的@deprecated与源代码中的@Deprecated
    android KE or NE分析
    Android手机中UID、PID作用及区别
    mtk刷机错误汇总
    区分Integer.getInteger和Integer.valueOf、Integer.parseInt() 的使用方法
    :>/dev/null 2>&1 的作用
    android 小技巧
    转:Eclipse自动补全功能轻松设置
    android开发常用地址
    转:大数据 2016 landscape
  • 原文地址:https://www.cnblogs.com/LukeStepByStep/p/7326139.html
Copyright © 2020-2023  润新知