P1099 树网的核——模拟+树形结构

P1099 树网的核

无根树,在直径上找到一条长度不超过s的路径,使得最远的点距离这条路径的距离最短;

首先两遍dfs找到直径(第二次找的时候一定要吧father[]清零)

在找到的直径下枚举长度不超过s的链,ans的下界是直径两端点到这条链距离的最小值;

然后将直径上的点都标记,再次求一下别的点到直径的距离。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int maxn=620;
 6 int n,s;
 7 int pre[maxn],last[maxn],other[maxn],len[maxn],l;
 8 
 9 void add(int x,int y,int z)
10 {
11     l++;
12     pre[l]=last[x];
13     last[x]=l;
14     other[l]=y;
15     len[l]=z;
16 }
17 
18 int dis[maxn],father[maxn],vis[maxn];
19 int l1,l2;
20 
21 void dfs(int x)
22 {
23     for(int p=last[x];p;p=pre[p])
24     {
25         int v=other[p];
26         if(v==father[x]||vis[v]) continue;
27         father[v]=x;
28         dis[v]=dis[x]+len[p];
29         dfs(v);
30     }
31 }
32 
33 
34 int main()
35 {
36     scanf("%d%d",&n,&s);
37     for(int i=1;i<n;i++)
38     {
39         int x,y,z;
40         scanf("%d%d%d",&x,&y,&z);
41         add(x,y,z);
42         add(y,x,z);
43     }    
44     
45     dis[1]=0; dfs(1);    
46     l1=1;
47     for(int i=1;i<=n;i++) if(dis[i]>dis[l1]) l1=i;
48     memset(father,0,sizeof(father));
49     dis[l1]=0; dfs(l1); l2=1;
50     for(int i=1;i<=n;i++) if(dis[i]>dis[l2]) l2=i;
51     
52     //printf("??%d %d\n",l1,l2);
53     
54     int ans=2147483647,j=l2;
55     for(int i=l2;i;i=father[i])
56     {
57         while(father[j]&&dis[i]-dis[father[j]]<=s) j=father[j];
58         ans=min(ans,max(dis[l2]-dis[i],dis[j]));
59     }
60     for(int i=l2;i;i=father[i]) vis[i]=1;
61     for(int i=l2;i;i=father[i]) 
62     {
63         dis[i]=0;
64         dfs(i);
65     }
66     for(int i=1;i<=n;i++) ans=max(ans,dis[i]);
67     printf("%d",ans);
68     return 0;
69 }
View Code

 

 

posted @ 2019-10-31 07:23  AiRomance  阅读(208)  评论(0编辑  收藏  举报