【POJ 1741】Tree
Time Limit: 1000MS
Memory Limit: 30000K
Total Submissions: 11570
Accepted: 3626
Description
Give a tree with n vertices,each edge has a length(positive integer less than 1001).
Define dist(u,v)=The min distance between node u and v.
Give an integer k,for every pair (u,v) of vertices is called valid if and only if dist(u,v) not exceed k.
Write a program that will count how many pairs which are valid for a given tree.
Input
The input contains several test cases. The first line of each test case contains two integers n, k. (n<=10000) The following n-1 lines each contains three integers u,v,l, which means there is an edge between node u and v of length l.
The last test case is followed by two zeros.
Output
For each test case output the answer on a single line.
Sample Input
5 4
1 2 3
1 3 1
1 4 2
3 5 1
0 0
Sample Output
8
Source
LouTiancheng@POJ
나의 포인트 1 번 문제 ~ ~ ~
나무의 경 로 는 두 종류 로 나 뉜 다.
뿌리 결산 점 통과 하기;근결 점 을 거치 지 않다.
그러면 우 리 는 모든 점 을 뿌리 로 선택 한 다음 에 이 노드 의 길 이 를 계산 할 수 있 습 니 다. < = k 의 경 로 를 계산 한 다음 에 똑 같은 방법 으로 그의 모든 서브 트 리 중의 경로 줄 수 를 계산 하면 무 겁 고 새 지 않 을 수 있 습 니 다.
루트 노드 와 길이 < = k 를 거 친 경로 개 수 를 어떻게 계산 합 니까?
모든 것 으로 같은 나무 에 있 는 것 을 빼 면 된다.
모든 길이 < = k 의 경 로 를 어떻게 계산 합 니까?
dfs 로 각 점 의 깊이 를 구하 고 하나의 배열 에 존재 한 다음 에 어 렸 을 때 부터 큰 줄 의 순서 까지 두 개의 지침 으로 쓸 었 다. l = 1, r = tot 는 l 이 증가 하 는 과정 에서 dep [l] + dep [r] < = k 의 r 지침 이 증가 하지 않 기 때문에 O (n) 는 풀 수 있 고 sort 의 O (nlogn) 를 더 하면 이 작업 의 복잡 도 는 O (nlogn) 이다.
그래서 전체적인 복잡 도 는 O (재 귀 층수 * nlogn) 인 데 어떻게 재 귀 층수 가 가장 적 게 합 니까?
매번 중심 (중심 찾기 [POJ 1655]) 을 근결 점 으로 하고 재 귀 층 수 는 logn 이다.
그래서 총 복잡 도 는 O (nlog ^ 2n) ~
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#define M 10005
using namespace std;
struct edge
{
int y,ne,l;
}e[M*100];
int ans,all,h[M],f[M],done[M],s[M],dep[M],tot=0,size,n,k,root;
void Addedge(int x,int y,int l)
{
tot++;
e[tot].y=y;
e[tot].ne=h[x];
e[tot].l=l;
h[x]=tot;
}
void Getroot(int x,int fa)
{
f[x]=0;
s[x]=1;
for (int i=h[x];i;i=e[i].ne)
{
int y=e[i].y;
if (y==fa||done[y]) continue;
Getroot(y,x);
s[x]+=s[y];
f[x]=max(f[x],s[y]);
}
f[x]=max(f[x],size-s[x]);
if (f[x]<f[root]) root=x;
}
void Getdep(int x,int fa,int de)
{
dep[++all]=de;
s[x]=1;
for (int i=h[x];i;i=e[i].ne)
{
int y=e[i].y,l=e[i].l;
if (y==fa||done[y]) continue;
Getdep(y,x,de+l);
s[x]+=s[y];
}
}
int calc(int x,int de)
{
int an=0;
all=0;
Getdep(x,0,de);
sort(dep+1,dep+1+all);
for (int l=1,r=all;l<r;)
if (dep[l]+dep[r]<=k) an+=r-l++;
else r--;
return an;
}
void Solve(int x)
{
ans+=calc(x,0);
done[x]=true;
for (int i=h[x];i;i=e[i].ne)
{
int y=e[i].y;
if (done[y]) continue;
ans-=calc(y,e[i].l);
size=f[0]=s[y];
Getroot(y,root=0);
Solve(root);
}
}
int main()
{
while (scanf("%d%d",&n,&k)==2)
{
if (n==k&&n==0) break;
tot=0;
for (int i=1;i<=n;i++)
h[i]=0,done[i]=false;
for (int i=1;i<n;i++)
{
int x,y,l;
scanf("%d%d%d",&x,&y,&l);
Addedge(x,y,l);
Addedge(y,x,l);
}
ans=0;
f[0]=size=n;
Getroot(1,root=0);
Solve(root);
printf("%d
",ans);
}
return 0;
}
깨 달 음:
1. TLE 는 Solve (root) 때문에 Solve (y) 라 고 썼 다.
2. 점 분 치 의 관건 은 경 로 를 통 해 근 결 점 과 근 결 점 을 거치 지 않 고 재 귀 방법 을 찾 는 것 이다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
정수 반전Udemy 에서 공부 한 것을 중얼거린다 Chapter3【Integer Reversal】 (예) 문자열로 숫자를 반전 (toString, split, reverse, join) 인수의 수치 (n)가 0보다 위 또는 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.