zoukankan      html  css  js  c++  java
  • POJ 1848 (一道不错的树形dp)

    题意:N个点的一颗树。问最少添加多少条边可以让每个点都在一个(且仅一个)环中。

    不得不佩服,这题dp设计出来的人。。。偶是弱菜,只能膜拜了。

    这位大牛的解说,很详细:http://hi.baidu.com/19930705cxjff/blog/item/1df66e4a4ff3022e08f7ef5d.html
     

    首先明确一点,题中的环至少需要3个顶点。因此,对于树中的每个顶点,有3种状态。
    f[x][0]表示以x为根的树,变成每个顶点恰好在一个环中的图,需要连的最少边数。
    f[x][1]表示以x为根的树,除了根x以外,其余顶点变成每个顶点恰好在一个环中的图,需要连的最少边数。
    f[x][2]表示以x为根的树,除了根x以及和根相连的一条链(算上根一共至少2个顶点)以外,其余顶点变成每个顶点恰好在一个环中的图,需要连的最少边数。
    有四种状态转移(假设正在考虑的顶点是R,有k个儿子):
    A.根R的所有子树自己解决(取状态0),转移到R的状态1。即R所有的儿子都变成每个顶点恰好在一个环中的图,R自己不变。



    B.根R的k-1个棵树自己解决,剩下一棵子树取状态1和状态2的最小值,转移到R的状态2。剩下的那棵子树和根R就构成了长度至少为2的一条链。


    C.根R的k-2棵子树自己解决,剩下两棵子树取状态1和状态2的最小值,在这两棵子树之间连一条边,转移到R的状态0。


    D.根R的k-1棵子树自己解决,剩下一棵子树取状态2(子树里还剩下长度至少为2的一条链),在这棵子树和根之间连一条边,构成一个环,转移到R的状态0。

     
     
    ps:写代码要有胆量,不要怕TLE。。。直接暴力枚举这些值就行。

    附代码:

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    #include <string>
    #include <set>
    #include <ctime>
    #include <queue>
    #include <map>
    #include <sstream>
    
    #define CL(arr, val)    memset(arr, (val), sizeof(arr))
    #define REP(i, n)       for((i) = 0; (i) < (n); ++(i))
    #define FOR(i, l, h)    for((i) = (l); (i) <= (h); ++(i))
    #define FORD(i, h, l)   for((i) = (h); (i) >= (l); --(i))
    #define L(x)    (x) << 1
    #define R(x)    (x) << 1 | 1
    #define MID(l, r)   ((l) + (r)) >> 1
    #define Min(x, y)   (x) < (y) ? (x) : (y)
    #define Max(x, y)   (x) < (y) ? (y) : (x)
    #define E(x)    (1 << (x))
    #define iabs(x)  ((x) > 0 ? (x) : -(x))
    
    typedef long long LL;
    const double eps = 1e-12;
    const int inf = 10000;  
    
    using namespace std;
    
    const int N = 110;
    
    struct node {
        int to;
        int next;
    } g[N<<2];    
    
    int head[N], t;
    
    bool vis[N];
    int f[N][3];
    
    void init() {
        CL(head, -1); t = 0;
    }
    
    void add(int u, int v) {
        g[t].to = v; g[t].next = head[u]; head[u] = t++;
    }
    
    void dfs(int t) {
        int i, j, k, v, sum = 0, tmp, n;
        vector<int> ch;
        for(i = head[t]; i != -1; i = g[i].next) {
            v = g[i].to;
            if(!vis[v]) {
                vis[v] = true;
                dfs(v);
                sum += f[v][0];
                ch.push_back(v);
            }
        }
        n = ch.size();
        if(n == 0) {
            //printf("%d here!\n", t);
            f[t][0] = inf;
            f[t][1] = 0;
            f[t][2] = inf;
            return ;
        }
    
    
        f[t][1] = min(inf, sum);
        f[t][0] = f[t][2] = inf;
    
        for(i = 0; i < n; ++i) {
            v = ch[i];
            f[t][2] = min(f[t][2], sum - f[v][0] + min(f[v][1], f[v][2]));
            f[t][0] = min(f[t][0], sum - f[v][0] + f[v][2] + 1);
        }
        for(i = 0; i < n; ++i) {
            v = ch[i];
            for(j = 0; j < n; ++j) {
                if(i == j)  continue;
                k = ch[j];
                tmp = sum - f[v][0] - f[k][0] + min(f[v][1], f[v][2]) + min(f[k][1], f[k][2]);
                f[t][0] = min(f[t][0], tmp + 1);
            }
        }
    }
    
    int main() {
        //freopen("data.in", "r", stdin);
    
        int n, x, y, i;
        while(~scanf("%d", &n)) {
            init();
            for(i = 1; i < n; ++i) {
                scanf("%d%d", &x, &y);
                add(x, y); add(y, x);
            }
            CL(vis, false); vis[1] = true;
            dfs(1);
            //for(i = 1; i <= n; ++i) printf("%d | %-11d %-11d %-11d\n", i, f[i][0], f[i][1], f[i][2]);
            if(f[1][0] >= inf)  puts("-1");
            else    printf("%d\n", f[1][0]);
        }
        return 0;
    }

     
     
     

     

  • 相关阅读:
    存储过程生成POCO
    Asp.net MVC4与Razor呈现图片的扩展
    Html5中新input标签与Asp.net MVC应用程序
    HTML5上传文件显示进度
    JQuery图表插件之Flot
    用Html5与Asp.net MVC上传多个文件
    TSQL列出最后访问的存储过程
    Asp.net MVC 限制一个方法到指定的Submit按钮
    VisualStudio2012轻松把JSON数据转换到POCO的代码
    Apache Tika源码研究(三)
  • 原文地址:https://www.cnblogs.com/vongang/p/2634763.html
Copyright © 2011-2022 走看看