P3761 [TJOI2017] 城市
P3761 [TJOI2017] 城市
从加里敦大学城市规划专业毕业的小明来到了一个地区城市规划局工作。这个地区一共有 \(n\) 座城市,\(n-1\) 条高速公路,保证了任意两运城市之间都可以通过高速公路相互可达,但是通过一条高速公路需要收取一定的交通费用。小明对这个地区深入研究后,觉得这个地区的交通费用太贵。
小明想彻底改造这个地区,但是由于上司给他的资源有限,因而小明现在只能对一条高速公路进行改造,改造的方式就是去掉一条高速公路,并且重新修建一条一样的高速公路(即交通费用一样),使得这个地区的两个城市之间的最大交通费用最小(即使得交通费用最大的两座城市之间的交通费用最小),并且保证修建完之后任意两座城市相互可达。如果你是小明,你怎么解决这个问题?
说明/提示
对于 \(100\%\) 的数据,\(1\leq n\leq 5000\)。
Solution:
又来朝花夕拾了 qwq.
题意转化:
给定一颗树,你可以断一条边然后再连一条长度相同的边,最小化新树的直径。
首先看到这个数据范围我们很难不想到 \(O(n^2)\) 。然后我们思考一下断一条边再连一条边对于树的直径有何影响:
我们考虑断掉 (u,v,w) 这条边,然后连 (x,y,w) 这条边。记 \(G'(u),G'(v)\) 表示断开 (u,v,w) 之后, u,v 所在的子图。\(x\in G'(u)\ \ y\in G'(v)\)。那么新树的直径有三种可能:\(G'(u)\) 的直径 \(d_u\) , \(G'(v)\) 的直径 \(d_v\) ,\(G'(u)\) 的半径 \(r_u\) + \(w\) + \(G'(v)\) 的半径 \(r_v\)。
所以我们要找一条边 (u,v,w) 将其断开之后最小化 \(Max{(d_u,d_v,r_u+w+r_v)}\) 然后我们发现 \(d,r\) 都是可以 \(O(n)\) 算出来的。
然后这题就做完了。
说句闲话:
猛然发现一年之前我的码风也是有十分好看的时候的,不经过刻意的压行,但是每行的长度区别不会太大,看得人心情还是挺舒畅的。要是换做现在的我来写,\(dfs\) 高低给你压进五行以内。
万恶的压行神教
Code:
#include<bits/stdc++.h>
const int N=10005;
const int inf=1e9;
using namespace std;
int head[N],cut[N<<2],fi[N],se[N],son[N],vis[N<<2];
int n,m,e_cnt=1,ans=inf;
struct Edge{
int to,nxt,w;
}e[N<<2];
void add(int x,int y,int w)
{
e[++e_cnt]={y,head[x],w};
head[x]=e_cnt;
}
void dfs(int x,int fa,int &res)
{
for(int i=head[x];i;i=e[i].nxt)
{
int to=e[i].to,w=e[i].w;
if(to==fa||cut[i])continue;
dfs(to,x,res);
res=max(res,fi[x]+w+fi[to]);
if(fi[x]<fi[to]+w)
{
se[x]=fi[x];
fi[x]=fi[to]+w;
son[x]=to;
}
else se[x]=max(se[x],fi[to]+w);
}
}
void dfs2(int x,int fa,int dis,int &res)//相当于找重心 但此处重心的定义为使x子树内所有点中到mid的最大距离最小化的点
{ //说人话就是使x这棵子树内半径最小的点 但是要求的不是重心,而是这个被最小化的半径
res=min(res,max(dis,fi[x]));//最小化半径
for(int i=head[x];i;i=e[i].nxt)
{
int to=e[i].to,w=e[i].w;
if(to==fa||cut[i])continue;
int new_dis=max(son[x]==to? se[x]:fi[x],dis)+w;
dfs2(to,x,new_dis,res);
}
}
void init()
{
memset(fi,0,sizeof(fi));
memset(se,0,sizeof(se));
memset(son,0,sizeof(son));
}
int main()
{
cin>>n;
for(int i=1,x,y,w;i<n;i++)
{
scanf("%d%d%d",&x,&y,&w);
add(x,y,w);
add(y,x,w);
}
int du,dv,ru,rv,ansd,ansr;
for(int i=2;i<=e_cnt;i+=2)
{
init();
cut[i]=cut[i^1]=1;
int v=e[i].to,w=e[i].w,u=e[i^1].to;
du=dv=0;
ru=rv=inf;
dfs(u,0,du);dfs(v,0,dv);
ansd=max(du,dv);
dfs2(u,0,0,ru);dfs2(v,0,0,rv);
ansr=ru+rv+w;
ans=min(ans,max(ansd,ansr));
cut[i]=cut[i^1]=0;
}
printf("%d",ans);
return 0;
}

浙公网安备 33010602011771号