zoukankan      html  css  js  c++  java
  • NOIP2007 树网的核

    题意简化

    给定一棵带边权无根树,在其直径上求出一段长度不超过s的路径F,使得离路径距离最远的点到路径的距离最短。
    传送门

    题解

    不难发现,对于直径上的任意一点,距离它最远的点一定是直径的某一端点
    所以我们不妨把这句话拓展一下

    对于任意一点距离它最远的点一定在直径上

    所以找直径的话,就是先随便找个点找到离他最远的点
    这个点一定在直径上
    然后再从这个点出发就能找到了直径的端点
    然后直接尺取法
    再把直径上的每个点都找一下最远的点就好

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define re register
    #define ll long long
    #define in inline
    #define get getchar()
    in int read()
    {
    	int t=0; char ch=get;
    	while(ch<'0' || ch>'9') ch=get;
    	while(ch<='9' && ch>='0') t=t*10+ch-'0',ch=get;
    	return t;
    }
    const int _=1001;
    int k,h[_],top,n,m,f[_],dis[_],vis[_],tot,ans=2e9;
    struct edge{
    	int to,ne,w;
    }e[_];
    in void add(int x,int y,int z)
    {
    	e[++tot].to=y,e[tot].ne=h[x],e[tot].w=z,h[x]=tot;
    }
    in void dfs(int x,int fa)
    {
    //	cout<<x<<endl;
    	f[x]=fa;
    	if(dis[x]>dis[k])k=x;
    	for(re int i=h[x];i;i=e[i].ne)
    	{
    		int y=e[i].to;
    		if(y==fa||vis[y])continue;
    		dis[y]=dis[x]+e[i].w;
    		dfs(y,x);
    	}
    }
    int main()
    {
    	n=read(),m=read();
    	for(re int i=1;i<n;i++)
    	{
    		int z=read(),y=read(),l=read();
    		add(z,y,l);
    		add(y,z,l);
    	}
    	dis[1]=1;dfs(1,0);
    	dis[k]=0;dfs(k,0);
    	top=k;
    	int x;
    	for(re int i=top,j=top;i;i=f[i])
    	{
            while(dis[j]-dis[i]>m)j=f[j];
            x=max(dis[top]-dis[j],dis[i]);
            ans=min(ans,x);
        }
    	for(re int i=top;i;i=f[i])vis[i]=1;
    	for(re int i=top;i;i=f[i])
    	{
            k=i,dis[k]=0;
            dfs(i,f[i]);
        }
    	for(re int i=1;i<=n;i++)
    		ans=max(ans,dis[i]);
    	cout<<ans<<endl;
    }
    
    
    嗯,就这样了...
  • 相关阅读:
    php utf-8
    thinkPHP--关于域名指向的问题
    PHP命名空间(Namespace)的使用详解
    thinkphp 动态配置
    枚举之称硬币
    5.7
    5.6
    5.5(OI一本通开始)
    5.4
    5.3
  • 原文地址:https://www.cnblogs.com/yzhx/p/10702763.html
Copyright © 2011-2022 走看看