hdu 4679 Terrorist’s destroy(树形DP)

题目链接:hdu 4679 Terrorist’s destroy

题意:

给一棵树,每条边上都有一个权值,去掉树上任意一条边之后,分成两个子树,两个子树的最长路与这条边上的权值相乘,的到一个乘积。问去掉那一条边可以使这个乘积最小。

题解:

首先我们先找到整棵树的直径(即最长的那条路)。

那么删边的时候有两种情况:

1. 这条边不是直径上的边。

2. 这条边是直径上的边。

对于第一种情况,直接用直径来乘就行了。

对于第二种情况,这样可以发现一个性质:两棵子树的最长路,一定是以整棵树的最长路的两个端点为起点的。然后O(n)预处理一下。

最后从直径的一个端点开始删边,然后更新答案。

 1 #include<bits/stdc++.h>
 2 #define mst(a,b) memset(a,b,sizeof(a))
 3 #define F(i,a,b) for(int i=a;i<=b;++i)
 4 using namespace std;
 5 
 6 const int N=1e5+7;
 7 int cas,n,ans,mi,mxlen,s,t,ds[N],dt[N],ms[N],mt[N];
 8 int g[N],v[N*2],nxt[N*2],idx[N*2],w[N*2],ed;
 9 void adg(int x,int y,int z,int i){v[++ed]=y,w[ed]=z,idx[ed]=i,nxt[ed]=g[x],g[x]=ed;}
10 
11 inline void up(int &a,int b){if(a<b)a=b;}
12 
13 void dfs(int x,int fa,int dep,int *dis)
14 {
15     dis[x]=dep;
16     for(int i=g[x];i;i=nxt[i])
17         if(v[i]!=fa)
18             dfs(v[i],x,dep+1,dis);
19 }
20 
21 void dfs2(int x,int fa,int *mx,int *dis)
22 {
23     mx[x]=dis[x];
24     for(int i=g[x];i;i=nxt[i])
25         if(v[i]!=fa)
26             dfs2(v[i],x,mx,dis),up(mx[x],mx[v[i]]);
27 }
28 
29 void find(int x,int fa)
30 {
31     for(int i=g[x];i;i=nxt[i])
32         if(v[i]!=fa)
33         {
34             int cost=(ds[x]+dt[v[i]]+1==mxlen?w[i]*max(ms[x],mt[v[i]]):w[i]*mxlen);
35             if(cost<mi)ans=idx[i],mi=cost;
36             else if(cost==mi&&idx[i]<ans)ans=idx[i];
37             find(v[i],x);
38         }
39 }
40 
41 int main(){
42     scanf("%d",&cas);
43     F(ic,1,cas)
44     {
45         mst(g,0),ed=0;
46         scanf("%d",&n);
47         F(i,1,n-1)
48         {
49             int x,y,z;
50             scanf("%d%d%d",&x,&y,&z);
51             adg(x,y,z,i),adg(y,x,z,i);
52         }
53         dfs(1,0,0,ds);
54         int tmp=0;
55         F(i,1,n)if(ds[i]>tmp)s=i,tmp=ds[i];
56         dfs(s,0,0,ds),tmp=0;
57         F(i,1,n)if(ds[i]>tmp)t=i,tmp=ds[i];//找到树的直径
58         dfs(t,0,0,dt),dfs2(s,0,mt,dt),dfs2(t,0,ms,ds);//预处理断掉该节点的一条边后最长的子树直径
59         mi=INT_MAX,mxlen=tmp;
60         find(s,0);
61         printf("Case #%d: %d
",ic,ans);
62     }
63     return 0;
64 }
View Code
原文地址:https://www.cnblogs.com/bin-gege/p/6439396.html