zoukankan      html  css  js  c++  java
  • 男人8题之 Tree (pku 1741)(树分治

    题目:求一棵树上路径长度小于k的路径条数。

    思路:这是LTC的男人八题里比较简单的一道。首先如果不是树,而是链的话,我们 可以想到一种分治算法(当然链的情况不分治更快),就是对于一个中点,对答案有贡献的要么是跨越中点的路径,要么是两边的路径,那么每次从中点分开,进行 分治的话复杂度是O(nlogn),对于这个树上的情况思路也是一样的,但是树上的分治有个比较特殊的地方是这个中点不太好找,需要跑一次dfs。然后对 每个分开的子树递归计算。我的实现总共用了5个递归,似乎可以少用一个(算子树的节点数目的时候),但是没想清楚怎么去,就索性直接又dfs了一遍。

    另外,除了这种点分治,还可以使用边分治,但是边分治有一种难以避免的使复杂度大大增加的情况(处理方法似乎比较复杂),所以树分治的首选还是点分治。

    /*
    * @author:  Cwind
    * http://www.cnblogs.com/Cw-trip/
    * 蒟蒻只能做几个水题。。
    */
    //#pragma comment(linker, "/STACK:102400000,102400000")
    #include <iostream>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <functional>
    #include <set>
    #include <cmath>
    using namespace std;
    #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0)
    #define pb push_back
    #define PB pop_back
    #define bk back()
    #define fs first
    #define se second
    #define sq(x) (x)*(x)
    #define eps 0.00000001
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF 1000000000
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> P;
    
    const int maxn=2e4+300;
    struct EDGE{
        int to,d;
    };
    vector<int> G[maxn];
    EDGE es[maxn];
    int eh;
    int center,mins;
    bool vis[maxn];
    vector<int> dis;
    int n,k;
    int cnt;
    int getCenter(int v,int f){
        int ssum=0,maxs=0;
        for(int i=0;i<G[v].size();i++){
            int e=G[v][i];
            int u=es[e].to;
            if(vis[u]||u==f) continue;
            int aa=getCenter(u,v);
            if(aa>maxs) maxs=aa;
            ssum+=aa;
        }
        if(max(maxs,cnt-ssum-1)<mins){
            center=v;
            mins=max(maxs,cnt-ssum-1);
        }
        return ssum+1;
    }
    void dfs(int v,int fore,int f){
        dis.pb(fore);
        for(int i=0;i<G[v].size();i++){
            int e=G[v][i];
            int u=es[e].to;
            if(vis[u]||u==f) continue;
            dfs(u,fore+es[e].d,v);
        }
    }
    void cont(int v,int f){
        cnt++;
        for(int i=0;i<G[v].size();i++){
            int e=G[v][i];
            int u=es[e].to;
            if(vis[u]||u==f) continue;
            cont(u,v);
        }
    }
    int cul(int v,int fore){
        int ans=0;
        dis.clear();
        dfs(v,fore,-1);
        sort(dis.begin(),dis.end());
        int p=0,q=dis.size()-1;
        while(p<=q){
            while(p<=q&&dis[q]+dis[p]>k) q--;
            if(p>q) break;
            ans+=q-p;
            p++;
        }
        return ans;
    }
    int solve(int v){
        vis[v]=1;
        int ans=0;
        ans+=cul(v,0);
        for(int i=0;i<G[v].size();i++){
            int e=G[v][i];
            int u=es[e].to;
            if(vis[u]) continue;
            ans-=cul(u,es[e].d);
            mins=1e8;
            cnt=0;
            cont(u,-1);
            getCenter(u,-1);
            ans+=solve(center);
        }
        return ans;
    }
    void addedge(int from,int to,int d){
        es[eh].to=to,es[eh].d=d;
        G[from].pb(eh++);
        es[eh].to=from,es[eh].d=d;
        G[to].pb(eh++);
    }
    void init(){
        eh=0;
        for(int i=0;i<=n;i++)
            G[i].clear();
        memset(vis,0,sizeof vis);
        dis.clear();
    }
    int main(){
        freopen("/home/files/CppFiles/in","r",stdin);
        //freopen("defense.in","r",stdin);
        //freopen("defense.out","w",stdout);
        while(cin>>n>>k){
            if(n==0&&k==0) break;
            init();
            for(int i=0;i<n-1;i++){
                int a,b,c;
                scanf("%d%d%d",&a,&b,&c);
                addedge(a,b,c);
            }
            mins=1e9;
            dfs(1,0,-1);
            cnt=0;
            cont(1,-1);
            getCenter(1,-1);
            cout<<solve(center)<<endl;
        }
        return 0;
    }
    View Code
  • 相关阅读:
    字符串动手动脑
    类与对象课后思考
    java动手动脑课后思考题
    java思考题
    《大道至简第二章读后感》
    从命令行接收多个数字,求和之后输出结果
    《大道至简》读后感
    团队项目成员和题目
    软件工程个人作业04
    软件工程个人作业03
  • 原文地址:https://www.cnblogs.com/Cw-trip/p/4792421.html
Copyright © 2011-2022 走看看