zoukankan      html  css  js  c++  java
  • 树的直径 练习

    随时会更新

    P4408

    根据题意可以发现构成的图是一棵树。
    然后可以发现行走路径是从 C 到距离较近的 A 或 B 点,再走完 A-B 路径,所以对于 A-B 路径,其长度与 C 的位置是无关的,所以他有一个固定的上限,在根据树的直径的性质,可以将其 A-B 确定为树的直径,之后我们要做的就是处理出直径一端点 A 与所有点的距离,另一端点 B 与所有点的距离,枚举一遍 n 更新答案即可。
    时间复杂度 (O(n))

    #include <cstdio>
    #include <algorithm>
    #define int long long 
    
    const int N=400070;
    struct Tree{ int to,nxt,w; }e[N];
    int n,m,cnt,maxdis,maxu,A,B;
    int head[N],d[2][N];
    void dfs(int u,int fa,int dis){
    	if(dis>maxdis) maxdis=dis,maxu=u;
    	for(int i=head[u],v;i;i=e[i].nxt){
    		v=e[i].to;if(v==fa) continue;
    		dfs(v,u,dis+e[i].w);
    	}
    }
    void DFS(int u,int fa,int k){
    	for(int i=head[u],v;i;i=e[i].nxt){
    		v=e[i].to;if(v==fa) continue;
    		d[k][v]=d[k][u]+e[i].w;
    		DFS(v,u,k);
    	}
    }
    void add(int from,int to,int val){e[++cnt].to=to,e[cnt].w=val,e[cnt].nxt=head[from],head[from]=cnt;}
    signed main(){
    	scanf("%lld%lld",&n,&m);
    	for(int i=1,u,v,w;i<=m;++i){
    		scanf("%lld%lld%lld",&u,&v,&w);
    		add(u,v,w),add(v,u,w);
    	}
    	dfs(1,0,0),maxdis=0,A=maxu,dfs(A,0,0),B=maxu,DFS(A,0,0),DFS(B,0,1);
    	int ans=0;
    	for(int i=1;i<=n;++i)
    		ans=std::max(ans,maxdis+std::min(d[0][i],d[1][i]));
    	printf("%lld
    ",ans);
    }
    

    P3639

    (k = 0) 时,因为要回到最终的起点,根据树的性质,我们可以迅速地得到答案为 (2*(n-1))
    (k = 1) 时,这条添加的边必须要遍历一遍,根据树的性质,添加一条边后树上肯定形成了一个环,所以整个环只需要遍历一遍,那我们要是减少的代价最多,根据树的性质,我们就需要找到树的直径,将两端相连,记直径的长度为 L1,
    这样我们此时的答案是 (2*(n-1)-L1+1)
    (k = 2) 时,根据之前的性质,我们原来的图中出现了两个环,若两个环没有重合的部分,那么我们的结论可以类比上题,但如果有重合的部分,此时我们肯定需要将重合的部分给去除掉,为了做到这一点,要做的就是将第一遍遍历得到的直径上所有边权改为 -1,再在新图上找一条新的直径,记直径的长度为 L2,很显然,答案是 (2*(n-1)-L1+1-L2+1)

    #include <cstdio>
    #include <algorithm>
    #include <map>
    
    const int N=200070;
    const int inf=1e9;
    struct Tree{ int to,nxt; }e[N];
    bool vis[N];
    std::map<int,int>mp[N];
    int n,k,cnt,maxdis,maxu,L1,L2;
    int head[N],f[N],pre[N],d[N];
    void add(int from,int to){e[++cnt].to=to,e[cnt].nxt=head[from],head[from]=cnt;}
    void dfs(int u,int fa,int dis){
    	if(dis>maxdis) maxdis=dis,maxu=u;
    	for(int i=head[u],v;i;i=e[i].nxt){
    		v=e[i].to;if(v==fa) continue;
    		dfs(v,u,dis+1);
    	}
    }
    void dfs2(int u,int fa,int dis){
    	if(dis>maxdis) maxdis=dis,maxu=u;
        pre[u]=fa;
    	for(int i=head[u],v;i;i=e[i].nxt){
    		v=e[i].to;if(v==fa) continue;
    		dfs2(v,u,dis+1);
    	}
    }
    int get(){
    	dfs(1,0,0),maxdis=0,dfs2(maxu,0,0);
    	return maxdis;
    }
    void modify(int u){
    	if(!u) return;
    	mp[u][pre[u]]=mp[pre[u]][u]=-1;
    	modify(pre[u]);
    }
    void dp(int u){
    	vis[u]=1;
    	for(int i=head[u],v;i;i=e[i].nxt){
    		v=e[i].to;if(vis[v]) continue;
    		dp(v),L2=std::max(L2,f[v]+f[u]+mp[u][v]),f[u]=std::max(f[u],f[v]+mp[u][v]);
    	}
    }
    int main(){
    	scanf("%d%d",&n,&k);
    	for(int i=1,u,v;i<n;++i){
    		scanf("%d%d",&u,&v);
    		add(u,v),add(v,u);
    		mp[u][v]=mp[v][u]=1;
    	}
    	L1=get();
    	if(k==1){
    		printf("%d
    ",2*(n-1)-L1+1);
    		return 0;
    	}
    	modify(maxu),dp(1);
    	printf("%d
    ",2*n-L1-L2);
    }
    
  • 相关阅读:
    更改文件默认打开方式
    python数据分析高频词提取,pyecharts词云制作并保存
    pyecharts V1.x版本使用Map绘制地图修改主题背景色等
    设置随机请求头和使用代理
    【重学前端】JS基础-原型和原型链
    【重学前端】JS基础-变量和类型
    Bootstrap blog整页制作
    拉勾网 移动端流式布局与rem布局整页制作
    PC端管理后台整页制作
    QQ飞车官方首页(部分)制作
  • 原文地址:https://www.cnblogs.com/Niuwadiandian/p/13959580.html
Copyright © 2011-2022 走看看