poj 1741
地址:http://poj.org/problem?id=1741
题意:给一棵无根树,求任意两点距离小于等于k的点对数量。
mark:男人八题。。http://wenku.baidu.com/view/e087065f804d2b160b4ec0b5.html###
上面网址是讲解思路的论文,具体实现没说。我来写写我的实现过程。
首先是要找到重心,那么先递归求出每个点拆掉后能够得到的最大的点的个数,这个点的个数最小的肯定是重心。
然后就按照论文讲解的方法求点对数量,先要求出每个点到重心的距离。
代码:
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <iostream> using namespace std; const int N = 10010; const int INF = 10000000; struct node { int v,w; int sum,maxv; //sum表示子孙节点个数,maxv表示拆了这个节点后剩余子树节点最多的个数 node *next; }*head[N],tree[2*N],tp[N]; int n,k,ptr,ans,root,tot; int w[N],vst[N]; int size[N],hash[N],dist[N]; //size表示最大分支的节点数 void init() { ans = ptr = 0; memset(vst, 0, sizeof(vst)); memset(head, 0, sizeof(head)); } void AddEdge(int x, int y, int z) { tree[ptr].v = y; tree[ptr].w = z; tree[ptr].next = head[x],head[x] = &tree[ptr++]; } void dfs(int s, int fa) { tp[s].sum = 1; tp[s].maxv = 0; node *p = head[s]; while(p != NULL) { if(p->v != fa && !vst[p->v]) { dfs(p->v, s); tp[s].sum += tp[p->v].sum; tp[s].maxv = max(tp[s].maxv, tp[p->v].sum); } p = p->next; } hash[tot] = s; size[tot++] = tp[s].maxv; } int getroot(int s) //求重心。 { tot = 0; dfs(s, 0); int tem = INF, maxr, cnt = tp[s].sum; for(int i = 0; i < tot; i++) { size[i] = max(size[i], cnt-size[i]); //是求每个点拆掉后能得到的子树最多的点的个数! if(size[i] < tem) { tem = size[i]; maxr = hash[i]; } } return maxr; } void getdis(int s, int fa, int dis) //求每个点到根节点的距离 { node *p = head[s]; dist[tot++] = dis; while(p != NULL) { if(p->v != fa && !vst[p->v] && dis+p->w <= k) getdis(p->v, s, dis+p->w); p = p->next; } } void count1(int s) //直接计算两点距离小于等于k的个数 { 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) //由于count1多算了在一条分支上的点,需要排除 { vst[s] = 1; node *p = head[s]; while(p != NULL) { if(!vst[p->v]) { tot = 0; getdis(p->v, s, p->w); 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--; } } p = p->next; } } void solve(int s, int fa) { root = getroot(s); tot = 0; getdis(root, 0, 0); count1(root); count2(root); node *p = head[root]; while(p != NULL) { if(p->v != fa && !vst[p->v]) solve(p->v, root); p = p->next; } } int main() { int i,j; while(scanf("%d%d", &n, &k), n+k) { init(); int aa,bb,cc; for(i = 1; i < n; i++) { scanf("%d%d%d", &aa, &bb, &cc); AddEdge(aa, bb, cc); AddEdge(bb, aa, cc); } solve(1, 0); printf("%d\n", ans); } }
posted on 2012-10-12 12:08 andre_joy 阅读(1290) 评论(0) 编辑 收藏 举报