• poj 1741 Tree


    题目大意:有一颗由n个点组成的树,问树上两点间距离小于等于k的点对有多少对
    输入:多组数据输入。每组数据第1行n,k,接下来n-1行,u,v,l表示点u与点v之间有一条长为l的边
    输出:点对个数

     

    /*
        借此题说说对点分治的认识,点分治就是将一棵树分为几部分,使得最大的一部分的点数最小,也就是找树的重心
        对于经过重心的,
        1、统计出过重心的所有点的满足条件的数目=ans1
        2、对于每棵子树,统计一遍自己内部满足条件的数目=ans2
        ans=ans1-所有的ans2
        对于不经过重心的,继续递归
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define INF 0x7fffffff
    #define maxn 10010
    struct node{int to,v,pre;}e[maxn*2];
    int n,num,k,root,sum,ans,head[maxn],f[maxn];
    int vis[maxn],son[maxn],d[maxn],dep[maxn];
    void Insert(int from,int to,int v){
        e[++num].to=to;
        e[num].v=v;
        e[num].pre=head[from];
        head[from]=num;
    }
    void getroot(int x,int fa){
        son[x]=1;f[x]=0;
        for(int i=head[x];i;i=e[i].pre){
            int to=e[i].to;
            if(to==fa||vis[to])continue;
            getroot(to,x);
            son[x]+=son[to];
            f[x]=max(f[x],son[to]);
        }
        f[x]=max(f[x],sum-son[x]);
        if(f[x]<f[root])root=x;
    }
    void getdeep(int x,int fa){
        dep[++dep[0]]=d[x];
        for(int i=head[x];i;i=e[i].pre){
            int to=e[i].to;
            if(to==fa||vis[to])continue;
            d[to]=d[x]+e[i].v;
            getdeep(to,x);
        }
    }
    int cal(int x,int v){
        d[x]=v;dep[0]=0;
        getdeep(x,0);
        sort(dep+1,dep+dep[0]+1);
        int l=1,r=dep[0],sum=0;
        while(l<r){
            if(dep[l]+dep[r]<=k){sum+=r-l;l++;}
            else r--;
        }
        return sum;
    }
    void solve(int x){
        ans+=cal(x,0);
        vis[x]=1;
        for(int i=head[x];i;i=e[i].pre){
            int to=e[i].to;
            if(vis[to])continue;
            ans-=cal(to,e[i].v);
            sum=son[to];
            root=0;
            getroot(to,0);
            solve(root);
        }
    }
    int main(){
        //freopen("Cola.txt","r",stdin);
        while(1){
            ans=0,root=0,num=0;
            memset(vis,0,sizeof(vis));
            memset(head,0,sizeof(head));
            scanf("%d%d",&n,&k);
            if(n==0&&k==0)break;
            for(int i=1;i<=n-1;i++){
                int x,y,z;
                scanf("%d%d%d",&x,&y,&z);
                Insert(x,y,z);Insert(y,x,z);
            }
            f[0]=INF;sum=n;
            getroot(1,0);
            solve(root);
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    剑指Offer 13.机器人的运动范围
    笔试题目-无向图是否全连通
    面试题目-最小代价的寻路问题
    京东一面问题
    剑指Offer 07.重建二叉树
    剑指Offer 12.矩阵中的路径
    剑指Offer 10-I.斐波那契数列
    剑指Offer 06.从尾到头打印链表
    剑指Offer 05.替换空格
    剑指Offer 04.二维数组中的查找
  • 原文地址:https://www.cnblogs.com/thmyl/p/8046001.html
Copyright © 2020-2023  润新知