hdu 3721 uvalive 5026 building roads

来源:互联网 发布:安卓源码如何生成apk 编辑:程序博客网 时间:2024/05/22 03:47

首先,我们证明一个结论:树的重心一定在树的直径上

树的直径指树上最长的一条路径,树的重心指树上所有点中到其余点最远距离最小的点

假设重心u不在直径上,那么它到距它最远点(x)的路径一定会和树的直径有交点v,否则这条路径会是新的直径的一部分,那么v到x的距离一定更小,所以重心一定在直径上


显然,我们需要移走直径上的一条边,并且移走这条边后,原来的树变成了两棵树(特殊情况是移走和叶子相连的一条边,但不影响)

那这样子,这两棵树,每棵树都有自己的直径d1,d2,那么将两棵树重新合并后,当前最优解tmp>=max(d1,d2)

我们在树1中和树2中分别找重心,新合并的树上任意点到最远点距离的最小值也可能是是树1中的重心的相对应的值x+树2中的重心相对应的值y+枚举的边长w

即tmp=max(tmp,w+x+y)


代码:

#include<iostream>#include<cstring>#include<cstdio>#include<algorithm>#include<cmath>#include<stack>#include<queue>#include<vector>#include<map>#include<ctime>using namespace std;const int MAX=2555;struct node {int v,w,next,flag;}g[MAX*10];int adj[MAX],e,n,m,dis[MAX],pre[MAX],D,tot,tmp[MAX],res[MAX];void add(int u,int v,int w){g[e].v=v; g[e].w=w; g[e].flag=1; g[e].next=adj[u]; adj[u]=e++;}void dfs(int u,int fa,int w,int id){int i,v;pre[u]=id;dis[u]=w;D=max(D,w);for(i=adj[u];i!=-1;i=g[i].next){v=g[i].v;if(v==fa||!g[i].flag)continue;dfs(v,u,w+g[i].w,i);}}void find(int root){memset(dis,0,sizeof(dis));dfs(root,-1,0,-1);int ma=-1,i,j;for(i=1;i<=n;i++)if(dis[i]>ma){ma=dis[i];j=i;}memset(dis,0,sizeof(dis));D=-1;dfs(j,-1,0,-1);}void find_path(int t,int res[],int &tot){int i;tot=0;for(i=pre[t];i!=-1;i=pre[g[i^1].v]){res[tot++]=i;}}void solve(){int ans,i,j,x,y,k;find(1);ans=1<<30;for(i=1;i<=n;i++){if(dis[i]==D){find_path(i,res,tot);break;}}//cout<<"tot="<<tot<<endl;for(i=0;i<tot;i++){//cout<<g[res[i]].v<<endl;g[res[i]].flag=0;g[res[i]^1].flag=0;find(g[res[i]].v);int d1=D,n1,n2;for(j=1;j<=n;j++){if(dis[j]==D){find_path(j,tmp,n1);break;}}if(d1==0)x=0;elsex=1<<30;for(j=0;j<n1;j++){k=g[tmp[j]].v;x=min(x,max(dis[k],D-dis[k]));k=g[tmp[j]^1].v;x=min(x,max(dis[k],D-dis[k]));}find(g[res[i]^1].v);int d2=D;for(j=1;j<=n;j++){if(dis[j]==D){find_path(j,tmp,n2);break;}}if(d2==0)y=0;elsey=1<<30;for(j=0;j<n2;j++){k=g[tmp[j]].v;y=min(y,max(dis[k],D-dis[k]));k=g[tmp[j]^1].v;y=min(y,max(dis[k],D-dis[k]));}g[res[i]].flag=1;g[res[i]^1].flag=1;d1=max(d1,d2);d1=max(d1,g[res[i]].w+x+y);ans=min(ans,d1);}printf("%d\n",ans);}int main(){int i,j,k,w,T;scanf("%d",&T);for(int ca=1;ca<=T;ca++){memset(adj,-1,sizeof(adj));e=0;scanf("%d",&n);for(i=1;i<n;i++){scanf("%d%d%d",&j,&k,&w);j++; k++;add(j,k,w); add(k,j,w);}printf("Case %d: ",ca);solve();}return 0;}