BZOJ4890 & 洛谷3761:[TJOI2017]城市——題解

https://www.lydsy.com/JudgeOnline/problem.php?id=4890php

https://www.luogu.org/problemnew/show/P3761node

從加里敦大學城市規劃專業畢業的小明來到了一個地區城市規劃局工做。這個地區一共有n座城市,n-1條高速公路,保證了任意兩運城市之間均可以經過高速公路相互可達,可是經過一條高速公路須要收取必定的交通費用。ios

小明對這個地區深刻研究後,以爲這個地區的交通費用太貴。小明想完全改造這個地區,可是因爲上司給他的資源有限,於是小明如今只能對一條高速公路進行改造,改造的方式就是去掉一條高速公路,而且從新修建一條同樣的高速公路(即交通費用同樣),使得這個地區的兩個城市之間的最大交通費用最小(即便得交通費用最大的兩座城市之間的交通費用最小),而且保證修建完以後任意兩座城市相互可達。若是你是小明,你怎麼解決這個問題?git

前置技能:樹直徑,樹半徑(代碼的樹半徑是我本身yy的請無視orz)spa

複雜度顯然是$O(n^2)$的,這就使咱們支持枚舉每條邊求出答案。code

設拆完路以後的兩棵樹爲$A,B$,那麼就有三種狀況:blog

最長路在$A$中資源

最長路在$B$中get

最長路端點分別在$A,B$中博客

前二者求樹直徑便可,至於最後一個咱們就須要考慮一個問題,到底要把邊加在哪裏才能使這種狀況的長度最小。

顯然是要加在樹半徑最小的兩個點上(懶得證了)。

因而切了(順便複習了怎麼求樹直徑和半徑,我以爲我多半是廢了基本技能都不會了。)

#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=5005;
const int INF=1e9;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
struct node{
    int w,to,nxt;
}e[N*2];
int n,cnt,head[N],f[N][3];
bool vis[N];
inline void add(int u,int v,int w){
    e[++cnt].to=v;e[cnt].w=w;e[cnt].nxt=head[u];head[u]=cnt;
}
int ans;
void dfs1(int u,int fa){
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to,w=e[i].w;
        if(vis[v]||fa==v)continue;
        dfs1(v,u);
        if(f[u][0]<f[v][0]+w){
            f[u][1]=f[u][0];
            f[u][0]=f[v][0]+w;
        }else if(f[u][1]<f[v][0]+w)
            f[u][1]=f[v][0]+w;
    }
    ans=max(ans,f[u][0]+f[u][1]);
}
void dfs2(int u,int fa){
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to,w=e[i].w;
        if(vis[v]||fa==v)continue;
        f[v][2]=f[u][2]+w;
        if(f[u][0]-w!=f[v][0])f[v][2]=max(f[v][2],f[u][0]+w);
        else f[v][2]=max(f[v][2],f[u][1]+w);
        dfs2(v,u);
    }
    ans=min(ans,max(f[u][0],f[u][2]));
}
int main(){
    n=read();
    for(int i=1;i<n;i++){
        int u=read(),v=read(),w=read();
        add(u,v,w);add(v,u,w);
    }
    int sum=INF;
    for(int i=1;i<=cnt;i+=2){
        int u=e[i].to,v=e[i+1].to,w=e[i].w;
        int w1,w2,tmp=0;
        vis[v]=1;
        memset(f,0,sizeof(f));
        ans=0;dfs1(u,0);tmp=max(tmp,ans);
        ans=INF;dfs2(u,0);w1=ans;
        vis[v]=0;vis[u]=1;
        ans=0;dfs1(v,0);tmp=max(tmp,ans);
        ans=INF;dfs2(v,0);w2=ans;
        vis[u]=0;
        tmp=max(tmp,w1+w2+w);
        sum=min(sum,tmp);
    }
    printf("%d\n",sum);
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

+本文做者:luyouqi233。               +

+歡迎訪問個人博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

相關文章
相關標籤/搜索