码迷,mamicode.com
首页 > 其他好文 > 详细

树的点分治 (poj 1741, 1655(树形dp))

时间:2014-08-08 12:25:25      阅读:246      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   color   os   io   for   art   

poj 1655:http://poj.org/problem?id=1655

题意: 给无根树,  找出以一节点为根,  使节点最多的树,节点最少。

题解:一道树形dp,先dfs 标记 所有节点的子树的节点数。 再dfs  找出以某节点为根的最大子树,节点最少。 复杂度(n)

bubuko.com,布布扣
/***Good Luck***/
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
#include <map>
#include <queue>
#include <vector>
#include <set>
#include <functional>
#include <cmath>

#define Zero(a) memset(a, 0, sizeof(a))
#define Neg(a)  memset(a, -1, sizeof(a))
#define All(a) a.begin(), a.end()
#define PB push_back
#define inf 0x7fffffff
#define inf2 0x7fffffffffffffff
#define ll long long
using namespace std;

const int maxn = 100000;
int n, k, e, head[maxn];
int mx[maxn], sum[maxn], ansn, ansb;
struct Node {
    int next, v;
}node[maxn];

void input(int u, int v) {
    node[e].next = head[u];
    node[e].v = v;
    head[u] = e++;
}

int dfssize(int b, int fa) {
    sum[b] = 1;
    mx[b] = 0;
    int tmpmx;
    for (int i = head[b]; ~i; i = node[i].next) {
        int v = node[i].v;
        if (fa != v) {
            tmpmx = dfssize(v, b);
            sum[b] +=tmpmx;            
            if (tmpmx > mx[b]) mx[b] = tmpmx;
        }
    }
    return sum[b];
}

void solve(int b, int fa) {
    int tmpmx;
    tmpmx = max(mx[b], n - sum[b]);
    if (tmpmx <= ansb) {
        if (tmpmx < ansb) {
            ansn = b;
            ansb = tmpmx;
        } else if (b < ansn) {
            ansn = b;
            ansb = tmpmx;
        }
    }
    for (int i = head[b]; ~i; i = node[i].next) {
        int v = node[i].v;
        if (fa != v) {
            solve(v, b);
        }
    }
}

int main() {
    int u, v;
    int T;
    scanf("%d", &T);
    while (T-- ) {
        scanf("%d", &n);
        e = 0;
        Neg(head);
        for (int i = 0; i < n - 1; ++i) {
            scanf("%d%d", &u, &v);
            input(u, v);
            input(v, u);
        }
        dfssize(1, 0);
        ansb = inf;
        solve(1, 0);
        printf("%d %d\n", ansn, ansb);
    }
    return 0;
}
View Code

poj 1741:http://poj.org/problem?id=1741

题意:给一值k,在带权无向图G中, 找出两节点相距不大于k的数。 

  qzc论文的第一题(膜拜q神  orz),根据论文写的 代码, 先写了一题树形dp(1655),再开始写这的,搞了一晚上具体的还是看论文吧。

找根(n), 计算(logn), 一共执行 logn次  总复杂度(n*logn*logn)

  1 /***Good Luck***/
  2 #define _CRT_SECURE_NO_WARNINGS
  3 #include <iostream>
  4 #include <cstdio>
  5 #include <cstdlib>
  6 #include <cstring>
  7 #include <string>
  8 #include <algorithm>
  9 #include <stack>
 10 #include <map>
 11 #include <queue>
 12 #include <vector>
 13 #include <set>
 14 #include <functional>
 15 #include <cmath>
 16 
 17 #define Zero(a) memset(a, 0, sizeof(a))
 18 #define Neg(a)  memset(a, -1, sizeof(a))
 19 #define All(a) a.begin(), a.end()
 20 #define PB push_back
 21 #define inf 0x3f3f3f3f
 22 #define inf2 0x7fffffffffffffff
 23 #define ll long long
 24 using namespace std;
 25 const int maxn = 20000;
 26 int head[maxn], n, k, e;
 27 int ans, sum[maxn], mx[maxn];
 28 bool vis[maxn];
 29 int dis[maxn], a[maxn], an;
 30 struct Node {
 31     int w;
 32     int v, next;
 33 }edge[maxn];
 34 
 35 void init() {
 36     e = 0;
 37     ans = 0;
 38     Neg(head);
 39     Zero(vis);
 40 }
 41 
 42 void add(int u, int v, int w) { //邻接表储存
 43     edge[e].v = v;
 44     edge[e].w = w;
 45     edge[e].next = head[u];
 46     head[u] = e++;
 47 }
 48 
 49 int dfssize(int u, int fa) {  //标记子树的节点数
 50     sum[u] = 1;
 51     mx[u] = 0;
 52     int tmpmx;
 53     for (int i = head[u]; ~i; i = edge[i].next) {
 54         int v = edge[i].v;
 55         if (v != fa && !vis[v]) {
 56             tmpmx = dfssize(v, u);
 57             sum[u] += tmpmx;
 58             if (tmpmx > mx[u]) mx[u] = tmpmx;
 59         }
 60     }
 61     return sum[u];
 62 }
 63 
 64 int ansn, mxshu;
 65 void find_root(int u, int fa, int nn) {  // 找出符合条件的根。
 66     int tmpmx = max(mx[u], nn - sum[u]);
 67     if (tmpmx < mxshu) {
 68         ansn = u;
 69         mxshu = tmpmx;
 70     }
 71     for (int i = head[u]; ~i; i = edge[i].next) {
 72         int v = edge[i].v;
 73         if (v != fa && !vis[v]) {
 74             find_root(v, u, nn);
 75         }
 76     }
 77 }
 78 
 79 void dfsdis(int u, int fa) {
 80     a[an++] = dis[u];
 81     for (int i = head[u]; ~i; i = edge[i].next) {
 82         int v = edge[i].v;
 83         if (fa != v && !vis[v]) {
 84             dis[v] = dis[u] + edge[i].w;
 85             dfsdis(v, u);
 86         }
 87     }
 88 }
 89 
 90 int cal(int u, int fa, int beg) {  //  这个方法太神奇了 复杂度只有 (logn)
 91     an = 0;
 92     int ret = 0;
 93     dis[u] = beg;
 94     dfsdis(u, fa);
 95     sort(a, a + an);
 96     int l = 0, r = an - 1;
 97     while (l < r) {
 98         if (a[r] + a[l] <= k )
 99             ret += r - l++;
100         else
101             r--;
102     }
103     return ret;
104 }
105 
106 void solve(int u) {
107     dfssize(u, 0);
108     mxshu = inf;
109     find_root(u, 0, sum[u]);
110     vis[ansn] = true;
111     ans += cal(ansn, 0, 0);
112     for (int i = head[ansn]; ~i; i = edge[i].next) {
113         int v = edge[i].v;
114         if (!vis[v]) {
115             ans -= cal(v, ansn, edge[i].w);
116             solve(v);
117         }
118     }
119 }
120 int main() {
121     //freopen("data.out", "w", stdout);
122     //freopen("data.in", "r", stdin);
123     int u, v, w;
124     while (scanf("%d%d", &n, &k), n&&k) {
125         init();
126         for (int i = 0; i < n - 1; ++i) {
127             scanf("%d%d%d", &u, &v, &w);
128             add(u, v, w);
129             add(v, u, w);
130         }
131         solve(1);
132         printf("%d\n", ans);
133     }
134     return 0;
135 }

 

 

 

树的点分治 (poj 1741, 1655(树形dp)),布布扣,bubuko.com

树的点分治 (poj 1741, 1655(树形dp))

标签:style   blog   http   color   os   io   for   art   

原文地址:http://www.cnblogs.com/yeahpeng/p/3898994.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!