基於點分治的樹分治
阿新 • • 發佈:2018-10-27
algorithm 計算 開始 tails 論文 continue dfsr size 多少
本文代碼來源:https://blog.csdn.net/yang_7_46/article/details/9966455
本文參考論文來源:https://wenku.baidu.com/view/8861df38376baf1ffc4fada8.html?re=view
基於點分治的樹分治算法
poj1741
基本步驟:1.一次dfs計算每個點的size
2.一次dfs找到重心
3.一次dfs計算每個點的深度
4.計算以root為重心情況下dis[u]+dis[v]<=k的點對數,u,v是root的兒子
5.遍歷root的各個子樹,對於每個子樹
(1):減去dis[u]+dis[v]<=k的點對數,u,v是當前子樹的兒子(為什麽要減去?dis[u]+dis[v]=u,v的路徑長度+2*dis[lca(u,v)],不是u,v的距離)
(2):開始分治
復雜度計算,分治復雜度O(logN),每次分治最大復雜度O(NlogN),總復雜度O(NlogN*logN)
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #define MAXN 10010 usingnamespace std; int N,K; int ans,root,Max; struct node{ int v,next,w; }edge[MAXN<<1]; int head[MAXN],tot; int size[MAXN]; int maxv[MAXN]; int vis[MAXN]; int dis[MAXN]; int num; void init(){ tot=ans=0; memset(head,-1,sizeof head); memset(vis,0,sizeof vis); } void addedge(int u,intv,int w){ edge[tot].v=v; edge[tot].w=w; edge[tot].next=head[u]; head[u]=tot++; } //一次dfs處理子樹的大小 void dfssize(int u,int f){ size[u]=1; maxv[u]=0; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(v==f||vis[v]) continue; dfssize(v,u); size[u]+=size[v]; if(size[u]>maxv[u])maxv[u]=size[u]; } } //一次dfs找重心,這裏的r不是重心 void dfsroot(int r,int u,int f){ if(size[r]-size[u]>maxv[u]) maxv[u]=size[r]-size[u]; if(maxv[u]<Max) Max=maxv[u],root=u; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(v==f||vis[v]) continue; dfsroot(r,v,u); } } //一次dfs求每個點到重心的距離 void dfsdis(int u,int d,int f){ dis[num++]=d; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(v!=f && !vis[v]) dfsdis(v,d+edge[i].w,u); } } int calc(int u,int d){ int ret=0; num=0; dfsdis(u,d,0);//求每個點到根的距離 sort(dis,dis+num); int i=0,j=num-1; while(i<j){ while(dis[i]+dis[j]>K && i<j) j--; ret+=j-i; i++; } return ret; } void dfs(int u){//註意這裏的u並不是重心 Max=N; dfssize(u,0);//求每個子樹的規模 dfsroot(u,u,0);//求重心 ans+=calc(root,0);//求以root為根,dis[u]+dis[v]的點對有多少 vis[root]=1;//把這個點從點集刪掉 for(int i=head[root];i!=-1;i=edge[i].next){ int v=edge[i].v; if(!vis[v]){ ans-=calc(v,edge[i].w); dfs(v); } } } int main(){ while(scanf("%d%d",&N,&K)!=EOF){ if(!N) break; int u,v,w; init(); for(int i=1;i<N;i++){ scanf("%d%d%d",&u,&v,&w); addedge(u,v,w); addedge(v,u,w); } dfs(1); printf("%d\n",ans); } return 0; }
基於點分治的樹分治