poj 1741 Tree 树的分治

来源:互联网 发布:淘宝怎么申请换货 编辑:程序博客网 时间:2024/06/05 17:18

这个题自己完全不会做,,,只是看了解题报告之后自己尝试写了一遍。发现思路很是清晰


首先是涉及到了树怎样进行分治,然后就引入了重心的概念,所谓树的重心就是删除这个点之后所得到的所有子树的最大顶点数最小,这样的话不管怎么切割这颗树,复杂度都不会退化得太严重


然后具体算法就是把这颗树以重心为顶点分为几颗子树,那么满足条件的点对,要么是在同一子树中,要么是在不同两颗子树中,要么其中一个点是重心,就这样递归处理这颗树就能得到答案了,不过在统计的时候有可能出现重复统计的时候,应当删除掉。


#include<iostream>#include<sstream>#include<cstdio>#include<cstring>#include<cmath>#include<queue>#include<stack>#include<math.h>#include<map>#include<time.h>#include<set>#include<string>#include<vector>#include<algorithm>using namespace std;#define inf 0x7fffffff#define lc l,m,index<<1#define rc m+1,r,index<<1|1#define max_n 200005#define mod 10000007#define LL  long longint n,k;struct edge{    int to,length;};int ans;vector<edge>G[max_n];int num[max_n]; //统计子树节点个数bool use[max_n]; //记录节点是否被当做重心void init(){    for(int i=0;i<=10005;i++)    G[i].clear();    memset(num,0,sizeof(num));    memset(use,false,sizeof(use));}int cntnum(int v,int p)   //返回子树节点个数{    int c=1;    for(int i=0;i<G[v].size();i++)    {        int w=G[v][i].to;        if(w!=p && !use[w])        {            c+=cntnum(w,v);        }    }    num[v]=c;    return c;}pair<int ,int > findcen(int v,int p,int t) //寻找重心,返回值为最大顶点数和顶点编号{    int s=1,m=0;    pair<int,int> res = make_pair(inf,-1);    for(int i=0;i<G[v].size();i++)    {        int w=G[v][i].to;        if(w==p || use[w])continue;        res=min(res,findcen(w,v,t));        s+=num[w];        m=max(m,num[w]);    }    m=max(t-s,m);    res=min(res,make_pair(m,v));    return res;}void findlen(int v,int p,int d,vector<int> &ds)  //记录其他点距离中心点的距离{    ds.push_back(d);    for(int i=0;i<G[v].size();i++)    {        int w=G[v][i].to;        if(w==p || use[w])continue;        findlen(w,v,d+G[v][i].length,ds);    }}int judge(vector<int> &ds){    int res=0;    sort(ds.begin(),ds.end());    int j=ds.size();    for(int i=0;i<ds.size();i++)    {        while(j>0 && ds[i]+ds[j-1]>k)j--;        res+=j-(j>i?1:0);    }  //  printf(" res ===  %d\n",res);    return res/2;}void solve_problem(int v)    //solve{    cntnum(v,-1);    int s=findcen(v,-1,num[v]).second;    use[s]=true;    //1    for(int i=0;i<G[s].size();i++)    {        if(use[G[s][i].to]) continue;        solve_problem(G[s][i].to);    }    //2,3;    vector<int> d;    d.push_back(0);    for(int i=0;i<G[s].size();i++)    {        int w=G[s][i].to;        if(use[w])continue;        vector<int>ds;        findlen(w,s,G[s][i].length,ds);        ans-=judge(ds);      //  printf("ans  == %d \n",ans);        d.insert(d.end(),ds.begin(),ds.end());    }    ans+=judge(d);   // printf("ans  ==  %d\n",ans);    use[s]=false;}void solve(){    ans=0;    solve_problem(1);    printf("%d\n",ans);}int main(){    while(~scanf("%d%d",&n,&k) && !(n==0 && k==0))    {        init();        for(int i=0;i<n-1;i++)        {            int a,b,l;            scanf("%d%d%d",&a,&b,&l);            edge e;            e.length=l;            e.to=b;            G[a].push_back(e);            e.to=a;            G[b].push_back(e);        }        solve();    }    return 0;}


0 0
原创粉丝点击