1. 程式人生 > >洛谷P3761:[TJOI2017]城市

洛谷P3761:[TJOI2017]城市

gpo add strong 輸入 規劃局 工作 遠的 tdi 直接

題目描述

從加裏敦大學城市規劃專業畢業的小明來到了一個地區城市規劃局工作。這個地區一共有ri座城市,《-1條高速公路,保證了任意兩運城市之間都可以通過高速公路相互可達,但是通過一條高速公路需要收取一定的交通費用。小明對這個地區深入研究後,覺得這個地區的交通費用太貴。小明想徹底改造這個地區,但是由於上司給他的資源有限,因而小明現在只能對一條高速公路進行改造,改造的方式就是去掉一條高速公路,並且重新修建一條一樣的高速公路(即交通費用一樣),使得這個地區的兩個城市之間的最大交通費用最小(即使得交通費用最大的兩座城市之間的交通費用最小),並且保證修建完之後任意兩座城市相互可達。如果你是小明,你怎麽解決這個問題?

輸入輸出格式

輸入格式

輸入數據的第一行為一個整數n,代表城市個數。

接下來的n - 1行分別代表了最初的n-1條公路情況。每一行都有三個整數u,v,d。u,v代表這條公路的兩端城市標號,d代表這條公路的交通費用。

1 <= u,v <= n,1<= d <= 2000

輸出格式

輸出數據僅有一行,一個整數,表示進行了最優的改造之後,該地區兩城市 之間最大交通費用。

輸入輸出樣例

輸入樣例#1:
5
1 2 1
2 3 2
3 4 3
4 5 4
輸出樣例#1:
7

說明

對於30%的數據,1<=n<500

對於100%的數據,1<=n<=5000


想法

很顯然,最優解中去掉的那條邊一定在原先這棵樹的直徑上,否則交通費用最大的兩個點之間距離沒有縮短。
n這麽小,可以枚舉每條去掉的邊。
去掉一條邊後原圖變為兩棵樹,將這兩棵樹連起來後,交通費用最大為max{第一棵樹的直徑,第二棵樹的直徑,兩棵樹的“重心”到最遠結點的距離和+這條邊的長度}
這裏所說的樹的“重心”指樹中的一個結點,它到樹中任意節點的距離最大值 最小

樹的直徑求法:
隨便找一個點u,找到樹中到它距離最遠的點v
再找到樹中到v距離最遠的點w,v到w的距離即為樹的直徑。
(簡單證明:假設樹的直徑為s-t 。首先對於s-t上任意一點,到它距離最遠的點為s或t;對於不在s-t上的點u,它與到它距離最遠的點之間的路徑上一定與s-t有相交,到這個交點距離最遠的點為s或t,則到u距離最遠的點為s或t)

樹的“重心”求法:
用兩個數組mx1[]與mx2[],分別記錄到某點u的最遠距離 及 次遠距離(次遠距離所在路徑與最遠距離所在路徑唯一交點為u
第一遍dfs,記錄結點u到其子樹中任意點的mx1[]與mx2[]
第二遍dfs,記錄節點u到整棵樹中任意點的mx1[]與mx2[]


代碼

(P.S.由於我太懶了,所以直接枚舉去掉每一條邊,不光是直徑上的[捂臉])

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>

#define INF 200000000

using namespace std;

const int N = 5005;

struct node{
    int v,len;
    node *next;
}pool[N<<1],*h[N];
int cnt;

void addedge(int u,int v,int len){
    node *p=&pool[++cnt],*q=&pool[++cnt];
    p->v=v;p->next=h[u];h[u]=p;p->len=len;
    q->v=u;q->next=h[v];h[v]=q;q->len=len;     
}

int dist[N],vis[N];
int dfs_len(int u,int vv){
    int v,w,ret=u;
    vis[u]=1; dist[u]=0;
    for(node *p=h[u];p;p=p->next)
        if(!vis[v=p->v] && v!=vv){
            w=dfs_len(v,vv);
            if(dist[u]<dist[v]+p->len){
                dist[u]=dist[v]+p->len;
                ret=w;
            }
        }
    vis[u]=0;
    return ret;
}
int diameter(int u,int vv){
    int v=dfs_len(u,vv);
    int w=dfs_len(v,vv);
    return dist[v];
}

int mx1[N],mx2[N];
void dfs1(int u,int vv){
    int v;
    vis[u]=1; 
    mx1[u]=mx2[u]=0;
    for(node *p=h[u];p;p=p->next)
        if(!vis[v=p->v] && v!=vv){
            dfs1(v,vv);
            if(mx1[u]<=mx1[v]+p->len){
                mx2[u]=mx1[u];
                mx1[u]=mx1[v]+p->len;     
            }
            else if(mx2[u]<mx1[v]+p->len)
                mx2[u]=mx1[v]+p->len;
        } 
    vis[u]=0;
}
int dfs2(int u,int vv){
    int v,w,ret;
    vis[u]=1;
    ret=mx1[u];
    for(node *p=h[u];p;p=p->next)
        if(!vis[v=p->v] && v!=vv){
            if(mx1[u]==mx1[v]+p->len)
                w=p->len+mx2[u];
            else w=p->len+mx1[u];
            if(w>=mx1[v])
                mx2[v]=mx1[v],mx1[v]=w;
            else if(w>mx2[v])
                mx2[v]=w;
            ret=min(ret,dfs2(v,vv));  
        }
    vis[u]=0;
    return ret;
}

int solve(int s,int t,int len){
    int ret=0,w=len;
    memset(vis,0,sizeof(vis));
    ret=max(diameter(s,t),diameter(t,s));
    dfs1(s,t); w+=dfs2(s,t); 
    dfs1(t,s); w+=dfs2(t,s); 
    return max(ret,w);
}

int fa[N];
int dfs(int u){
    int v,ret=INF;
    for(node *p=h[u];p;p=p->next)
        if(!fa[v=p->v]){
            ret=min(ret,solve(u,v,p->len));
            fa[v]=u;
            ret=min(ret,dfs(v));
        }
    return ret;
}
int n;

int main()
{
    int u,v,len;
    scanf("%d",&n);
    for(int i=1;i<n;i++)
        scanf("%d%d%d",&u,&v,&len),addedge(u,v,len);
    
    fa[1]=-1;
    printf("%d\n",dfs(1));
    
    return 0;    
}

洛谷P3761:[TJOI2017]城市