hdu 4679 Terrorist’s destroy 树形DP
链接:http://acm.hdu.edu.cn/showproblem.php?pid=4679
题意:给定一颗树,每条边有一个权值w,问切掉哪条边之后,分成的两颗树的较大的直径*切掉边的权值最小?如果存在多条边使得结果相同,输出边id最小的
思路:
dept一次找出最深的节点,之后以最深的节点出发(rt1)dept找到树的直径(即找到rt2);将路径保存在f[]中;
之后分别从rt1/rt2进行深搜,找到以一个节点为根的树的直径,这样在每次dfs之后,可以求出每条边的一边的最值,这样两次取max之后就求出了切掉该边之后得到的结果
注:
如果改变在整棵树的直径上,需要取出以该棵树为根的树的直径maxn[0][v];否则就直接取整棵树的直径即可;
在dfs递推出以某根为子树的直径时,可能直径不过根节点所以要将子子树的直径递推到子树上;
1 #include<bits/stdc++.h>
2 #pragma comment(linker, "/STACK:1024000000,1024000000") //加栈
3 using namespace std;
4 #define rep0(i,l,r) for(int i = (l);i < (r);i++)
5 #define rep1(i,l,r) for(int i = (l);i <= (r);i++)
6 #define rep_0(i,r,l) for(int i = (r);i > (l);i--)
7 #define rep_1(i,r,l) for(int i = (r);i >= (l);i--)
8 #define MS0(a) memset(a,0,sizeof(a))
9 #define MS1(a) memset(a,-1,sizeof(a))
10 #define MSi(a) memset(a,0x3f,sizeof(a))
11 #define inf 0x3f3f3f3f
12 #define lson l, m, rt << 1
13 #define rson m+1, r, rt << 1|1
14 typedef pair<int,int> PII;
15 #define A first
16 #define B second
17 #define MK make_pair
18 typedef long long ll;
19 typedef unsigned int uint;
20 template<typename T>
21 void read1(T &m)
22 {
23 T x=0,f=1;char ch=getchar();
24 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
25 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
26 m = x*f;
27 }
28 template<typename T>
29 void read2(T &a,T &b){read1(a);read1(b);}
30 template<typename T>
31 void read3(T &a,T &b,T &c){read1(a);read1(b);read1(c);}
32 template<typename T>
33 void out(T a)
34 {
35 if(a>9) out(a/10);
36 putchar(a%10+'0');
37 }
38 #define N 100007
39 int head[N<<1],tot;
40 struct edge{
41 int to,w,id,Next;
42 }e[N<<1];
43 void ins(int a,int b,int w,int id)
44 {
45 e[++tot].Next = head[a];
46 e[tot].to = b;
47 e[tot].w = w;
48 e[tot].id = id;
49 head[a] = tot;
50 }
51 int dep[N],p[N];
52 void dept(int u,int pre)
53 {
54 p[u] = pre;
55 dep[u] = dep[pre] + 1;
56 for(int id = head[u];id;id = e[id].Next){
57 int v = e[id].to;
58 if(v == pre) continue;
59 dept(v,u);
60 }
61 }
62 int f[N],maxlen;//树的直径
63 int aux[N];
64 int maxn[3][N];
65 void dfs(int u,int pre)
66 {
67 maxn[0][u] = maxn[1][u] = maxn[2][u] = 0;
68 for(int id = head[u];id;id = e[id].Next){
69 int v = e[id].to;
70 if(v == pre) continue;
71 dfs(v,u);
72 if(maxn[1][u] <= maxn[1][v]+1){
73 maxn[2][u] = maxn[1][u];
74 maxn[1][u] = maxn[1][v]+1;
75 }else if(maxn[2][u] < maxn[1][v]+1)
76 maxn[2][u] = maxn[1][v]+1;
77 if(maxn[0][u] < maxn[0][v]) //**可能树的直径不过根节点;
78 maxn[0][u] = maxn[0][v];
79 }
80 maxn[0][u] = max(maxn[0][u],maxn[1][u] + maxn[2][u]); //以u为根的子树的直径
81 }
82 void solve(int u,int pre)
83 {
84 for(int id = head[u];id;id = e[id].Next){
85 int v = e[id].to, w = e[id].w;
86 if(v == pre) continue;
87 if(f[u] && f[v]){ //边在直径上
88 aux[e[id].id] = max(aux[e[id].id],w*maxn[0][v]);
89 }else{
90 aux[e[id].id] = max(aux[e[id].id],w*maxlen);
91 }
92 solve(v,u);
93 }
94 }
95 int main()
96 {
97 //freopen("data.txt","r",stdin);
98 //freopen("out.txt","w",stdout);
99 int kase = 1,T,n;
100 read1(T);
101 while(T--){
102 MS0(head);tot = 0;
103 MS0(f);
104 read1(n);
105 rep0(i,1,n){
106 int u,v,w;
107 read3(u,v,w);
108 ins(u,v,w,i);ins(v,u,w,i);
109 }
110 dep[0] = 0;
111 dept(1,0);
112 int rt1 ,rt2 ,d = 0;
113 rep1(i,1,n) if(d < dep[i]) d = dep[i],rt1 = i;
114 dept(rt1,0);
115 d = 0;
116 rep1(i,1,n) if(d < dep[i]) d = dep[i],rt2 = i;
117 maxlen = d-1; //求出树的直径;以及两端的节点标号
118 int index = rt2;
119 while(index){
120 f[index] = 1;
121 index = p[index]; //从树直径的终点递推到起点
122 }
123 MS0(aux);
124 dfs(rt1,-1);
125 solve(rt1,0);
126 dfs(rt2,-1);
127 solve(rt2,0);
128 int ans = inf;
129 rep0(i,1,n){
130 if(ans > aux[i]) ans = aux[i],index = i;
131 }
132 printf("Case #%d: %d\n",kase++,index);
133 }
134 return 0;
135 }