zoukankan      html  css  js  c++  java
  • [hdu4714 Tree2cycle]树形DP

    题意:给一棵树,删边和加边的代价都为1,求把树变成一个圈所花的最小代价。

    思路:对原树进行删边操作,直到将原树分成若干条链,然后通过在链之间添加边形成圈,由于删边和加边一一对应,且最后需要额外一条边连成圈,所以有:

    最小代价=(最小链数-1)*2+1=最小链数*2-1。

    令dp[i][0]表示i不和i的父亲相连,i这颗子树所形成的最少链数,dp[i][1]表示i和i的父亲相连,i这颗子树所形成的最少链数,则:

    dp[i][0]=∑dp[j][0]+dp[p][1]-dp[p][0] + dp[q][1]-dp[q][0]-1

    dp[i][1]=∑dp[j][0]+dp[p][1]-dp[p][0]

    其中,j是i的子节点,p是满足dp[j][1]-dp[j][0]最小的j,q是满足dp[j][1]-dp[j][0]第二小的j。

     

      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    #pragma comment(linker, "/STACK:10240000")
    #include <map>
    #include <set>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <cstdio>
    #include <string>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    #define X                   first
    #define Y                   second
    #define pb                  push_back
    #define mp                  make_pair
    #define all(a)              (a).begin(), (a).end()
    #define fillchar(a, x)      memset(a, x, sizeof(a))
    #define copy(a, b)          memcpy(a, b, sizeof(a))
    
    typedef long long ll;
    typedef pair<int, int> pii;
    typedef unsigned long long ull;
    
    //#ifndef ONLINE_JUDGE
    void RI(vector<int>&a,int n){a.resize(n);for(int i=0;i<n;i++)scanf("%d",&a[i]);}
    void RI(){}void RI(int&X){scanf("%d",&X);}template<typename...R>
    void RI(int&f,R&...r){RI(f);RI(r...);}void RI(int*p,int*q){int d=p<q?1:-1;
    while(p!=q){scanf("%d",p);p+=d;}}void print(){cout<<endl;}template<typename T>
    void print(const T t){cout<<t<<endl;}template<typename F,typename...R>
    void print(const F f,const R...r){cout<<f<<", ";print(r...);}template<typename T>
    void print(T*p, T*q){int d=p<q?1:-1;while(p!=q){cout<<*p<<", ";p+=d;}cout<<endl;}
    //#endif
    template<typename T>bool umax(T&a, const T&b){return b<=a?false:(a=b,true);}
    template<typename T>bool umin(T&a, const T&b){return b>=a?false:(a=b,true);}
    
    const double PI = acos(-1.0);
    const int INF = 1e9 + 7;
    const double EPS = 1e-12;
    
    /* -------------------------------------------------------------------------------- */
    
    const int maxn = 1e6 + 7;
    
    pii E[maxn * 2];
    int SZ;
    int Next[maxn * 2];
    int last[maxn];
    int son[maxn];
    
    void add(int u, int v) {
        E[SZ ++] = mp(u, v);
        E[SZ ++] = mp(v, u);
        Next[SZ - 2] = last[u];
        last[u] = SZ - 2;
        Next[SZ - 1] = last[v];
        last[v] = SZ - 1;
    }
    
    int vis[maxn], dp[maxn][2];
    
    void dfs(int rt) {
        vis[rt] = true;
        int ans = 0, minv1 = INF, minv2 = INF, sum = 0, sum1 = 0, cnt = 0;
        for (int i = last[rt]; ~i; i = Next[i]) {
            int v = E[i].Y;
            if (!vis[v]) {
                dfs(v);
                cnt ++;
                sum += dp[v][0];
                sum1 += dp[v][1];
                int buf = dp[v][1] - dp[v][0];
                if (buf < minv1) {
                    minv2 = minv1;
                    minv1 = buf;
                }
                else {
                    if (buf < minv2) minv2 = buf;
                }
            }
        }
        if (cnt == 0) dp[rt][0] = dp[rt][1] = 1;
        else if (cnt == 1) dp[rt][0] = dp[rt][1] = sum1;
        else if (cnt >= 2) {
            dp[rt][0] = sum + minv1 + minv2 - 1;
            dp[rt][1] = sum + minv1;
        }
    //    printf("%d: %d %d
    ", rt, dp[rt][0], dp[rt][1]);
    }
    
    
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
        //freopen("out.txt", "w", stdout);
    #endif // ONLINE_JUDGE
        int T;
        cin >> T;
        while (T --) {
            int n;
            cin >> n;
            SZ = 0;
            fillchar(last, - 1);
            fillchar(Next, - 1);
            for (int i = 1; i < n; i ++) {
                int u, v;
                scanf("%d%d", &u, &v);
                add(u, v);
            }
            fillchar(vis, 0);
            dfs(1);
            cout << dp[1][0] * 2 - 1 << endl;
        }
        return 0;
    }
    
  • 相关阅读:
    Windows Azure Cloud Service (14) 使用Windows Azure诊断收集日志记录数据
    Windows Azure Cloud Service (13) 用Visual Studio 2010 将应用程序部署到Windows Azure平台
    Windows Azure Cloud Service (15) 多个VM Instance场景下如何处理ASP.NET Session
    Windows Azure Storage (5) Windows Azure Drive
    Windows Azure Storage (7) 使用工具管理Windows Azure Storage
    SQL Azure(二) SQL Azure vs SQL Server
    webbrowser的自动提交
    提取视频的背景声音的软件
    Listview列排序的bug原因
    两个奇怪的问题
  • 原文地址:https://www.cnblogs.com/jklongint/p/4743917.html
Copyright © 2011-2022 走看看