1. 程式人生 > >BZOJ4890 & 洛谷3761:[TJOI2017]城市——題解

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

set read sum style 復雜度 即使 truct logs algorithm

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

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

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

小明對這個地區深入研究後,覺得這個地區的交通費用太貴。小明想徹底改造這個地區,但是由於上司給他的資源有限,因而小明現在只能對一條高速公路進行改造,改造的方式就是去掉一條高速公路,並且重新修建一條一樣的高速公路(即交通費用一樣),使得這個地區的兩個城市之間的最大交通費用最小(即使得交通費用最大的兩座城市之間的交通費用最小),並且保證修建完之後任意兩座城市相互可達。如果你是小明,你怎麽解決這個問題?

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

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

設拆完路之後的兩棵樹為$A,B$,那麽就有三種情況:

最長路在$A$中

最長路在$B$中

最長路端點分別在$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/+

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

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