[Tjoi2017]城市

Posted cutemush

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Tjoi2017]城市相关的知识,希望对你有一定的参考价值。

从加里敦大学城市规划专业毕业的小明来到了一个地区城市规划局工作。这个地区一共有ri座城市,《-1条高速公
路,保证了任意两运城市之间都可以通过高速公路相互可达,但是通过一条高速公路需要收取一定的交通费用。小
明对这个地区深入研究后,觉得这个地区的交通费用太贵。小明想彻底改造这个地区,但是由于上司给他的资源有
限,因而小明现在只能对一条高速公路进行改造,改造的方式就是去掉一条高速公路,并且重新修建一条一样的高
速公路(即交通费用一样),使得这个地区的两个城市之间的最大交通费用最小(即使得交通费用最大的两座城市
之间的交通费用最小),并且保证修建完之后任意两座城市相互可达。如果你是小明,你怎么解决这个问题?
Input
输入数据的第一行为一个整数n,代表城市个数。
接下来的n - 1行分别代表了最初的n-1条公路情况。
每一行都有三个整数u,v,d。u,v代表这条公路的两端城市标号,d代表这条公路的交通费用。
1<=n<=5000
1 <= u,v <= n,1<= d <= 2000
Output
输出数据仅有一行,一个整数,表示进行了最优的改造之后,该地区两城市 之间最大交通费用。
Sample Input
5
1 2 1
2 3 2
3 4 3
4 5 4
Sample Output
7

/*
此题同ioi2013 dreaming那个题
枚举下删除的哪一条边,于是整个树变成两个连通块
对于连通块找出其半径,半径就是树中每个点的最长链的最小值
因为是希望找出新树的直径尽可能小嘛!
于是新树的直径可以是原来两个树的直径之一,可是用某条边连接其半径所形成 
*/ 
#include<bits/stdc++.h>
#define N 5007
#define inf 0x3f3f3f3f
using namespace std;
int n,m,ans,cnt,dis,res;
int head[N<<1],mv[N],u[N],v[N],w[N];
int dp[N][2];
bool vis[N];
struct edge
{
    int u,v,w,nxt;
}e[N<<1];

inline void add(int u,int v,int w)
{
    e[++cnt].v=v;
	e[cnt].w=w;
	e[cnt].nxt=head[u];
	head[u]=cnt;
}

inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c>‘9‘||c<‘0‘){if(c==‘-‘)f=-1;c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();}
    return x*f;
}

void getd(int u)
{
    for(int i=head[u];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if(vis[v]) continue;
        vis[v]=1;
		getd(v);
        if(dp[u][0]<dp[v][0]+e[i].w)
        {
            dp[u][1]=dp[u][0];mv[u]=v;
            dp[u][0]=dp[v][0]+e[i].w;
        }
        else if(dp[u][1]<dp[v][0]+e[i].w)
            dp[u][1]=dp[v][0]+e[i].w;
    }
	dis=max(dis,dp[u][0]+dp[u][1]);
}

void getr(int u,int from)
{
    res=min(res,max(from,dp[u][0]));
    //半径为每个点的最长链中的最小值 
    for(int i=head[u];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if(!vis[v]) continue;
        vis[v]=0;
        if(mv[u]==v) 
          getr(v,max(dp[u][1]+e[i].w,from+e[i].w));
        else 
          getr(v,max(dp[u][0]+e[i].w,from+e[i].w));
        
    }
}

void clear()
{
    memset(dp,0,sizeof dp);
    memset(mv,0,sizeof mv);
    memset(vis,0,sizeof vis);
    res=inf;dis=0;
}

int main()
{
    n=read();
    for(int i=1;i<n;i++)
    {
        u[i]=read();v[i]=read();w[i]=read();
        add(u[i],v[i],w[i]);add(v[i],u[i],w[i]);
    }
    int d1,d2,r1,r2;ans=res=inf;dis=0;
    for(int i=1;i<n;i++) //枚举删除哪一条边 
    {
        vis[v[i]]=1;//设第i条边被删除,设右端点已走过 
		getd(u[i]); //从左端点开始,求这个连通块的直径 
		d1=dis;
        dis=0;
		getd(v[i]); 
		d2=dis;
      
        vis[v[i]]=0;
		getr(u[i],0); 
		r1=res;
        res=inf;
		getr(v[i],0); 
		r2=res;
        //联通块1,2的半径 
        ans=min(ans,max(max(d1,d2),r1+r2+w[i]));
        //新树直径可能是原来两个树的直径,或用w[i]连接两个树的半径形成,取其最大值 
        clear();
    }
    printf("%d
",ans);
    return 0;
}

  

 

以上是关于[Tjoi2017]城市的主要内容,如果未能解决你的问题,请参考以下文章

[TJOI2017]城市(未解决)

[TJOI2017]城市 树的直径+暴力+优化

洛谷P3761:[TJOI2017]城市

P3761 [TJOI2017]城市

P3761 [TJOI2017]城市

P3761 [TJOI2017]城市