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 }

 

posted @ 2016-07-09 18:39  hxer  阅读(262)  评论(0编辑  收藏  举报