hdu4679 Terrorist’s destroy 解题报告
2013-08-18 15:50
267 查看
题意:给你一棵树和边上的权值,定义去掉一条边的花费为边权值(a)乘上b,b定义为去掉边后形成的两棵树中两点间的最远距离(注意是各自内部的最远距离),问去掉哪条边的花费最少?
分析:首先我们可以将树的直径找出来,如下图
假设1->6就是这棵树的直径,非直径上的边为枝条,有两种删除边的方式:
1.去掉的是枝条
2.去掉的是直径上的边
方式1:b值一定是直径长度,可以枚举直接处理。
方式2:我们先把直径上的点做预处理,dep[i]表示第i个点的最深的枝条深度(如dep[1] = 1; dep[2] = 2; dep[3] = 3; dep[4] = 1; dep[5] = 2;dep[6] = 1)
f1[i] 表示删除第i个点右边的边左侧能得到的b值 f2[i] 表示删除第i个点左边的边右侧能得到的b值
(如f1[1] = 0; f1[2] = 2; f1[3] = 4; f1[4] =4; f1[5] =5; ) 那么f1 ,f2的值怎么求呢? 可以证明f1的值只能是(一部分直径+一条枝条的长度)或是一部分直径的长度,绝不可能是由两段枝条组成。
所以我们有递推式 f1[i] = max{f1[i-1],i-1+dep[i]-1} 注意:这里的i是指从左边数第几个点,并非编号
f2递推式类似,有了f1和f2数组我们就可以枚举直径上的边了,从而在O(1)的时间算得每次的花费
c++代码
分析:首先我们可以将树的直径找出来,如下图
假设1->6就是这棵树的直径,非直径上的边为枝条,有两种删除边的方式:
1.去掉的是枝条
2.去掉的是直径上的边
方式1:b值一定是直径长度,可以枚举直接处理。
方式2:我们先把直径上的点做预处理,dep[i]表示第i个点的最深的枝条深度(如dep[1] = 1; dep[2] = 2; dep[3] = 3; dep[4] = 1; dep[5] = 2;dep[6] = 1)
f1[i] 表示删除第i个点右边的边左侧能得到的b值 f2[i] 表示删除第i个点左边的边右侧能得到的b值
(如f1[1] = 0; f1[2] = 2; f1[3] = 4; f1[4] =4; f1[5] =5; ) 那么f1 ,f2的值怎么求呢? 可以证明f1的值只能是(一部分直径+一条枝条的长度)或是一部分直径的长度,绝不可能是由两段枝条组成。
所以我们有递推式 f1[i] = max{f1[i-1],i-1+dep[i]-1} 注意:这里的i是指从左边数第几个点,并非编号
f2递推式类似,有了f1和f2数组我们就可以枚举直径上的边了,从而在O(1)的时间算得每次的花费
c++代码
#include<cstdio> #include<cstring> const int INF = 2000000000; const int MAXX = 200020; int q[MAXX],dislong[MAXX],f1[MAXX],f2[MAXX],pre[MAXX],father[MAXX],dep[MAXX]; int list[MAXX],next[MAXX],p[MAXX],c[MAXX],order[MAXX],maxx,n; bool b[MAXX],inlong[MAXX]; int getmax(int x,int y) { return x>y?x:y; } int getmin(int x,int y) { return x>y?y:x; } int findlong(int xx,int n) { int t,w,now,k,x; for (int i = 1; i <= n; i++) { b[i] = true; } t = 0; w = 1; q[1] = xx; dislong[1] = 1; b[xx] = false; pre[xx] = 0; maxx = 0; while (t < w) { t++; x = q[t]; k = list[x]; while (k > 0) { if (b[p[k]] == true) { w++; b[p[k]] = false; q[w] = p[k]; dislong[w] = dislong[t]+1; pre[p[k]] = x; if (dislong[w] > maxx) {maxx = dislong[w]; now = p[k];} } k = next[k]; } } return now; } void init(int n) { for (int i = 1; i <= n; i++) { list[i] = 0; } } void dfs(int x,int pre1) { int k; dep[x] = 1; k = list[x]; while (k > 0) { if (inlong[p[k]] == false && p[k] != pre1) { dfs(p[k],x); dep[x] = getmax(dep[x],dep[p[k]]+1); } k = next[k]; } } void finddep() { int i; for (i = 1; i <= n; i++) if (inlong[i]) { dfs(i,0); } } int main() { int step,temp,kase,tot,i,k,kk,x,y,z,front,rear; int sum,ans,result; scanf("%d",&temp); for (kase = 1; kase <= temp; kase++) { tot = 0; scanf("%d",&n); init(n); for (i = 1;i < n; i++) { scanf("%d%d%d",&x,&y,&z); tot++; next[tot] = list[x]; list[x] = tot; p[tot] = y; c[tot] = z; order[tot] = i; tot++; next[tot] = list[y]; list[y] = tot; p[tot] = x; c[tot] = z; order[tot] = i; } if (n != 1) { memset(pre,0,sizeof(pre)); front = findlong(1,n); rear = findlong(front,n); sum = maxx-1; k = rear; memset(inlong,false,sizeof(inlong)); memset(father,0,sizeof(father)); while (k > 0) { inlong[k] = true; father[pre[k]] = k; k = pre[k]; } memset(dep,0,sizeof(dep)); finddep();// //cong front -> rear memset(f1,0,sizeof(f1)); memset(f2,0,sizeof(f2)); k = front; step = 0; while (k != rear) { step++; f1[k] = getmax(f1[pre[k]],step-1+dep[k]-1); //? k = father[k]; } // cong rear->front k = rear; step = 0; father[rear] = 0; while (k != front) { step++; f2[k] = getmax(f2[father[k]],step-1+dep[k]-1); k = pre[k]; } //遍历直径 ans = INF; result = INF; k = front; while (k != rear) { kk = list[k]; while (kk > 0) { if (p[kk] == father[k]) break; kk = next[kk]; } if (ans > c[kk]*getmax(f1[k],f2[father[k]])) { ans = c[kk]*getmax(f1[k],f2[father[k]]); result = order[kk]; } else if (ans == c[kk]*getmax(f1[k],f2[father[k]])) { if (result > order[kk]) result = order[kk]; } k = father[k]; } //遍历枝条 for (i = 1; i <= n; i++) { k = list[i]; while (k > 0) { if(!(inlong[i] && inlong[p[k]])) { if (ans > c[k]*sum) { ans = c[k]*sum; result = order[k]; } else if (ans == c[k]*sum) { if (result > order[k]) result = order[k]; } } k = next[k]; } } printf("Case #%d: ",kase); printf("%d\n",result); } } return 0; }
相关文章推荐
- HDU 4679 Terrorist’s destroy 解题报告
- 【解题报告】HDU 4679 Terrorist’s destroy -- 树形dp 删一边求两子树直径
- hdu4679 Terrorist’s destroy(树形dp)
- CodeForces 115C. Plumber 解题报告
- [leetcode] 221. Maximal Square 解题报告
- 1048. Find Coins (25)解题报告
- 【LeetCode】435.Non-overlapping Intervals(Medium)解题报告
- hdu 2013 ACM/ICPC Asia Regional Online —— Warmup解题报告
- BZOJ 2428 模拟退火 解题报告
- 【LeetCode】75.Sort Colors(Medium)解题报告
- poj 2421 Constructing Roads 解题报告
- [leetcode] 9. Palindrome Number 解题报告
- Leetcode 441. Arranging Coins 硬币放置 解题报告
- 【解题报告】NYOJ471 好多的树 -- 容斥原理
- POJ-2386___水洼——解题报告 DFS
- HDU 4371 Minimum palindrome 解题报告(找规律)
- [Leetcode] 298. Binary Tree Longest Consecutive Sequence 解题报告
- 【解题报告】2011 Multi-University Training Contest 1-Host by HNU
- Sicily 4190. Prime Palindromes 解题报告
- 哈理工hrbust OJ 2225 解题报告