@Acqua
2019-01-26T09:53:38.000000Z
字数 5774
阅读 1374
模型 未完成
定义:树上的最长简单路。
说明:因为树上两点间简单路唯一,所以记树上两点间简单路为。
求法:次,第一次找出离根最远的点,记为;第二次找出离最远的点,这两点就是直径的端点[1]。
性质:
1. 对于树的直径,都是叶子结点(广义上的叶子结点是度为的结点,即对于广义叶子结点,除非外树上结点作为根节点,都有点为狭义叶子结点)[2]。
2. 对于树上任一结点,与其距离最远的结点一定在直径端点上[3]。
3. 对于直径为的树和直径为的树,两树合并后的直径[4]。
4. 若一棵树存在多条直径,那么这些直径交于一点且交点是这些直径的中点[5]。
5. 对于一棵树,如果在一个点的上接一个叶子节点,那么最多会改变直径端点集中的一个端点[6]。
代码:
// La Pluie#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int N=4e4+5;struct edge{int v,w,next;} e[N<<1];int n,m,head[N],root,ans,k=1;void adde(int u,int v,int w){e[k]=(edge){v,w,head[u]};head[u]=k++;}void dfs(int u,int f,int s){if(s>ans) root=u,ans=s;for(int i=head[u];i!=-1;i=e[i].next){int v=e[i].v,w=e[i].w;if(v==f) continue;dfs(v,u,s+w);}}int main(){memset(head,-1,sizeof(head));scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){int u,v,w;char c;scanf("\n%d %d %d %c",&u,&v,&w,&c);adde(u,v,w);adde(v,u,w);}dfs(1,0,0);dfs(root,0,0);printf("%d",ans);return 0;}
定义:树上的一个点,去掉后能使得到的森林中结点数最多的树结点数最少。
求法:记以为根的子树中结点数为(不包含),则。统计最小的,将加入答案数组(注意:树的重心一般不止一个)。
代码:
// La Pluie#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int N=5e4+5;struct edge{int v,next;}e[N<<1];int head[N],size[N],k=1,ans=1e9,res[N],t,n;void adde(int u,int v){e[k]=(edge){v,head[u]};head[u]=k++;}void dfs(int u,int f){int son=0;for(int i=head[u];i!=-1;i=e[i].next){int v=e[i].v;if(v==f) continue;dfs(v,u);son=max(son,size[v]);size[u]+=size[v];}int tmp=max(son,n-size[u]-1);if(ans>tmp){ans=tmp;t=0;res[++t]=u;}else if(ans==tmp) res[++t]=u;size[u]++;}int main(){memset(head,-1,sizeof(head));scanf("%d",&n);for(int i=1;i<n;i++){int u,v;scanf("%d%d",&u,&v);adde(u,v);adde(v,u);}dfs(1,0);sort(res+1,res+t+1);for(int i=1;i<=t;i++){printf("%d ",res[i]);}return 0;}