poj 1741 Tree (点的分治)

来源:互联网 发布:手机数据分析软件 编辑:程序博客网 时间:2024/05/21 08:40

题意:给你一棵树,问在树上有多少点对之间的最短距离小于等于K,且(a,b)和(b,a)算一个

思路:这题可以用点的分治来做,选取点为这棵树的重心,即最大子树最小的点。然后可以分两种情况进行处理,过这一点与不过这一点,而不过这一点就递归处理它的子树即可。

在统计的时候要注意,先算出到根节点的距离,然后排序,存入一个队列当中,统计时则可以根据头尾两个数相加来决定中间数的大小,因而 可以进行快速的统计。但是要注意减去一些情况,比如2结点到3结点经过1结点的距离计算时都要经过1到其儿子结点的一条边。这不是最短的要排除。

这里计算重心时我只是用了一个DFS,感觉应该可以快些。

代码如下:

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>#define inf 10000000using namespace std;const int maxn=11111;struct node{    int to;    int next;    int w;};node edge[maxn<<2];int head[maxn];int dp[maxn];int vis[maxn];int wei_cen;int dist[maxn];int tot;int minn;int ans;int e_sz;int n;int k;void init(){    memset(head,-1,sizeof(head));    memset(vis,0,sizeof(vis));    e_sz=0;    ans=0;}void addedge(int a,int b,int c)//加边{    edge[e_sz].to=b;    edge[e_sz].w=c;    edge[e_sz].next=head[a];    head[a]=e_sz++;}int dfs_cal(int u,int fa,int size)//计算重心{    dp[u]=1;    int maxx=0;    for(int i=head[u];i!=-1;i=edge[i].next)    {        int v=edge[i].to;        if(v!=fa&&(!vis[v]))        {            dfs_cal(v,u,size);            dp[u]+=dp[v];            maxx=max(maxx,dp[v]);        }    }    maxx=max(maxx,size-dp[u]);    if(minn>maxx)    {        minn=maxx;        wei_cen=u;    }    return wei_cen;}void getdis(int u,int fa,int dis)//求距离{    dist[tot++]=dis;    for(int i=head[u];i!=-1;i=edge[i].next)    {        int v=edge[i].to;        if((v!=fa)&&(!vis[v])&&(dis+edge[i].w<=k))        {            getdis(v,u,dis+edge[i].w);        }    }}void count1(int s)//计算点对数目{    sort(dist,dist+tot);    int left=0,right=tot-1;    while(left<right)    {        if(dist[left]+dist[right]<=k)        {            ans+=right-left;            left++;        }        else        {            right--;        }    }}void count2(int s)// 除去不可行的{    vis[s]=1;    for(int i=head[s];i!=-1;i=edge[i].next)    {        int v=edge[i].to;        if(!vis[v])        {            tot=0;            getdis(v,s,edge[i].w);            sort(dist,dist+tot);            int left=0;            int right=tot-1;            while(left<right)            {                if(dist[left]+dist[right]<=k)                {                    ans-=right-left;                    left++;                }                else                {                    right--;                }            }        }    }}void dfs(int s,int fa,int size)//递归求解{    minn=inf;    int root=dfs_cal(s,fa,size);    tot=0;  //  cout<<root<<endl;    getdis(root,0,0);    count1(root);    count2(root);   // cout<<ans<<endl;    for(int i=head[root];i!=-1;i=edge[i].next)    {        int v=edge[i].to;        if(v!=fa&&(!vis[v]))        {           // cout<<s<<" "<<v<<endl;            dfs(v,root,dp[v]);        }    }}int main(){   // freopen("in.txt","r",stdin);    while(scanf("%d%d",&n,&k),n||k)    {        init();        for(int i=0;i<n-1;i++)        {            int a,b,c;            scanf("%d%d%d",&a,&b,&c);            addedge(a,b,c);            addedge(b,a,c);        }        dfs(1,0,n);        printf("%d\n",ans);    }    return 0;}


原创粉丝点击