[BZOJ4890][TJOI2017]城市(DP)
题目描述
从加里敦大学城市规划专业毕业的小明来到了一个地区城市规划局工作。这个地区一共有ri座城市,《-1条高速公路,保证了任意两运城市之间都可以通过高速公路相互可达,但是通过一条高速公路需要收取一定的交通费用。小明对这个地区深入研究后,觉得这个地区的交通费用太贵。小明想彻底改造这个地区,但是由于上司给他的资源有限,因而小明现在只能对一条高速公路进行改造,改造的方式就是去掉一条高速公路,并且重新修建一条一样的高速公路(即交通费用一样),使得这个地区的两个城市之间的最大交通费用最小(即使得交通费用最大的两座城市之间的交通费用最小),并且保证修建完之后任意两座城市相互可达。如果你是小明,你怎么解决这个问题?
输入输出格式
输入格式:
输入数据的第一行为一个整数n,代表城市个数。
接下来的n - 1行分别代表了最初的n-1条公路情况。每一行都有三个整数u,v,d。u,v代表这条公路的两端城市标号,d代表这条公路的交通费用。
1 <= u,v <= n,1<= d <= 2000
输出格式:
输出数据仅有一行,一个整数,表示进行了最优的改造之后,该地区两城市 之间最大交通费用。
输入输出样例
说明
对于30%的数据,1<=n<500
对于100%的数据,1<=n<=5000
枚举选择哪条边将它切断,然后对分成的两棵树分别求树内最长链和到以某结点为端点的最长链的最小值,更新答案。
显然这条边一定在树的直径上,如果加入此优化可以快十多倍。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (register int i=l; i<=r; i++) 4 #define For(i,x) for (register int i=h[x],k; i; i=nxt[i]) 5 using namespace std; 6 7 const int N=100100,inf=1000000000; 8 int n,u,v,w,cnt,mn,mn1,tmp,ans,to[N],h[N],val[N],nxt[N],mx1[N],mx2[N],pre[N]; 9 void add(int u,int v,int w){ to[++cnt]=v; val[cnt]=w; nxt[cnt]=h[u]; h[u]=cnt; } 10 11 void dfs(int x,int fa){ 12 mx1[x]=mx2[x]=pre[x]=0; 13 For(i,x) if ((k=to[i])!=fa){ 14 dfs(k,x); int t=mx1[k]+val[i]; 15 if (t>mx1[x]) mx2[x]=mx1[x],mx1[x]=t,pre[x]=k; 16 else if (t>mx2[x]) mx2[x]=t; 17 tmp=max(tmp,mx1[x]+mx2[x]); 18 } 19 } 20 21 void dfs2(int x,int fa){ 22 mn=min(mn,mx1[x]); 23 For(i,x) if ((k=to[i])!=fa){ 24 int t=(pre[x]==k) ? mx2[x]+val[i] : mx1[x]+val[i]; 25 if (t>mx1[k]) mx2[k]=mx1[k],mx1[k]=t,pre[k]=x; 26 else if (t>mx2[k]) mx2[k]=t; 27 dfs2(k,x); 28 } 29 } 30 31 int main(){ 32 scanf("%d",&n); ans=inf; 33 rep(i,1,n-1) scanf("%d%d%d",&u,&v,&w),add(u,v,w),add(v,u,w); 34 rep(i,1,n-1){ 35 u=to[i*2-1]; v=to[i*2]; w=val[i*2]; tmp=0; 36 dfs(v,u); mn=inf; dfs2(v,u); mn1=mn; 37 dfs(u,v); mn=inf; dfs2(u,v); 38 ans=min(ans,max(tmp,mn+mn1+w)); 39 } 40 printf("%d\n",ans); 41 return 0; 42 }