Terrorist’s destroy HDU - 4679

There is a city which is built like a tree.A terrorist wants to destroy the city's roads. But now he is alone, he can only destroy one road, then the city will be divided into two cities. Impression of the city is a number defined as the distance between the farthest two houses (As it relates to the fare).When the terrorist destroyed a road, he needs to spend some energy, assuming that the number is a.At the same time,he will get a number b which is maximum of the Impression of two cities. The terrorist wants to know which road to destroy so that the product of a and b will be minimized.You should find the road's id. 
Note that the length of each road is one. 

InputThe first line contains integer T(1<=T<=20), denote the number of the test cases. 
For each test cases,the first line contains a integer n(1 < n <= 100000);denote the number of the houses; 
Each of the following (n-1) lines contains third integers u,v,w, indicating there is a road between house u and houses v,and will cost terrorist w energy to destroy it.The id of these road is number from 1 to n-1.(1<=u<=n , 1<=v<=n , 1<=w<=10000)OutputFor each test case, output the case number first,and then output the id of the road which the terrorist should destroy.If the answer is not unique,output the smallest id.Sample Input

2
5
4 5 1
1 5 1
2 1 1
3 5 1
5
1 4 1
1 3 1
5 1 1
2 5 1

Sample Output

Case #1: 2
Case #2: 3 题意:给出一颗树,删除其中的一个边,随后变成了两颗树,两颗树的直径为l1和l2,剪掉的边长为x,要求x*max(l1,l2)最小,求删除的是第几条边
思路:1.剪掉的是原来树上的枝,那么就是原来树的直径*删除的那条边的长度
   2.删除的是原来树上的直径的某一条,那么肯定是直径的一部分加枝条*删除的那条变的长度
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<cmath>
#include<stack>
#include<cstdlib>
#include <vector>
#include<queue>
using namespace std;
const int INF = ;
const int maxn = ;
int q[maxn],dislong[maxn],deleteLeft[maxn],deleteRight[maxn],pre[maxn],father[maxn],dep[maxn];
int list[maxn],Next[maxn],p[maxn],c[maxn],id[maxn],maxx,n;
bool b[maxn],inlong[maxn]; int findlong(int xx,int n)
{
int t,w,now,k,x;
for (int i = ; i <= n; i++)
{
b[i] = true;
}
t = ; w = ;
q[] = xx;
dislong[] = ;
b[xx] = false;
pre[xx] = ;
maxx = ;
while (t < w)
{
t++; x = q[t];
k = list[x];
while (k > )
{
if (b[p[k]] == true)
{
w++;
b[p[k]] = false;
q[w] = p[k];
dislong[w] = dislong[t]+;
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 = ; i <= n; i++)
{
list[i] = ;
}
}
void dfs_dep(int x,int pre1)
{
int k;
dep[x] = ;
k = list[x];
while (k > )
{
if (inlong[p[k]] == false && p[k] != pre1)
{
dfs_dep(p[k],x);
dep[x] = max(dep[x],dep[p[k]]+);
}
k = Next[k];
}
} int main()
{
int t;
scanf("%d",&t);
int ca = ;
while(t--)
{
int tot = ;
scanf("%d",&n);
init(n);
for (int i = ;i < n; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
tot++;
Next[tot] = list[u];
list[u] = tot;
p[tot] = v;
c[tot] = w;
id[tot] = i;
tot++;
Next[tot] = list[v];
list[v] = tot;
p[tot] = u;
c[tot] = w;
id[tot] = i;
}
if (n != )
{
memset(pre,,sizeof(pre));
int front = findlong(,n);
int rear = findlong(front,n);
int sum = maxx-; int k = rear;
memset(inlong,false,sizeof(inlong));
memset(father,,sizeof(father));
while (k > )
{
inlong[k] = true;
father[pre[k]] = k;
k = pre[k];
}
memset(dep,,sizeof(dep));
for(int i=;i<=n;i++)
if(inlong[i])
dfs_dep(i,);
memset(deleteLeft,,sizeof deleteLeft);
memset(deleteRight,,sizeof deleteRight);
k = front;
int step = ;
while (k != rear)
{
step++;
deleteLeft[k] = max(deleteLeft[pre[k]],step-+dep[k]-);
k = father[k];
} k = rear; step = ;
father[rear] = ;
while (k != front)
{
step++;
deleteRight[k] = max(deleteRight[father[k]],step-+dep[k]-);
k = pre[k];
}
//遍历直径
int ans = INF;
int result = INF;
k = front;
int kk;
while (k != rear)
{
kk = list[k];
while (kk > )
{
if (p[kk] == father[k]) break;
kk = Next[kk];
}
if (ans > c[kk]*max(deleteLeft[k],deleteRight[father[k]]))
{
ans = c[kk]*max(deleteLeft[k],deleteRight[father[k]]);
result = id[kk]; }
else if (ans == c[kk]*max(deleteLeft[k],deleteRight[father[k]]))
{
if (result > id[kk]) result = id[kk];
}
k = father[k];
} //遍历枝条
for (int i = ; i <= n; i++)
{
k = list[i];
while (k > )
{
if(!(inlong[i] && inlong[p[k]]))
{
if (ans > c[k]*sum)
{
ans = c[k]*sum;
result = id[k]; }
else if (ans == c[k]*sum)
{
if (result > id[k]) result = id[k];
}
}
k = Next[k];
}
}
printf("Case #%d: %d\n",ca++,result); }
}
return ;
}

网上也有思路说之间dfs直径的两个端点,但是会爆栈,要手动添栈,但在hdu上交了一发不用加栈。代码如下

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<cmath>
#include<stack>
#include<cstdlib>
#include <vector>
#include<queue>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = ;
struct Edge
{
int to,next;
int id,w;
}edge[maxn*];
int mm[maxn*];
int maxx[maxn],smaxx[maxn],head[maxn],tot;
int ans;
int dep[maxn];
int p[maxn];
bool used[maxn];
int cnt;
int Index;
int a[maxn];
void init()
{
memset(head,-,sizeof head);
tot = ;
} void addedge(int u,int v,int w,int id)
{
edge[tot].to = v;
edge[tot].w = w;
edge[tot].id = id;
edge[tot].next = head[u];
head[u] = tot++;
edge[tot].to = u;
edge[tot].w = w;
edge[tot].id = id;
edge[tot].next = head[v];
head[v] = tot++;
}
void dfs1(int u,int pre)
{
p[u] = pre;
dep[u] = dep[pre] + ;
for(int i = head[u]; i != -;i = edge[i].next)
{
int v = edge[i].to;
if(v==pre)continue;
dfs1(v,u);
}
}
void dfs(int u,int pre)
{
mm[u] = ;
maxx[u] = ;
smaxx[u] = ;
for(int i = head[u];i != -;i = edge[i].next)
{
int v = edge[i].to;
if(v == pre)continue;
dfs(v,u);
if(maxx[v]+ > smaxx[u])
{
smaxx[u] = maxx[v] + ;
if(smaxx[u] > maxx[u])
{
swap(smaxx[u],maxx[u]);
}
}
if(mm[v] > mm[u])
mm[u] = mm[v];
}
mm[u] = max(mm[u],maxx[u]+smaxx[u]);
}
void solve(int u,int pre)
{
for(int i = head[u];i != -;i = edge[i].next)
{
int v = edge[i].to;
int w = edge[i].w;
if(v == pre)continue;
solve(v,u);
if(used[v])
{
a[edge[i].id] = max(a[edge[i].id],w*mm[v]);
}
else
{
a[edge[i].id] = max(a[edge[i].id],w*cnt);
}
}
} int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T;
int n;
scanf("%d",&T);
int u,v,w;
int iCase = ;
while(T--)
{
iCase ++;
init();
scanf("%d",&n);
for(int i = ;i < n;i++)
{
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w,i);
}
dep[] = ;
dfs1(,);
u = ;
for(int i = ;i <= n;i++)
if(dep[u] < dep[i])
u = i;
dfs1(u,);
v = ;
for(int i =;i <= n;i++)
if(dep[v] < dep[i])
v = i;
cnt = dep[v]-;
memset(used,false,sizeof(used));
int tmp = v;
while(tmp)
{
used[tmp] = true;
tmp = p[tmp];
}
for(int i = ;i <= n;i++)
a[i] = ;
ans = INF;
dfs(u,);
solve(u,-);
dfs(v,);
solve(v,-);
for(int i = ;i < n;i++)
if(a[i]<ans)
{
ans = a[i];
Index = i;
}
printf("Case #%d: %d\n",iCase,Index);
} return ;
}

Terrorist’s destroy HDU - 4679的更多相关文章

  1. HDU 4679 Terrorist’s destroy (2013多校8 1004题 树形DP)

    Terrorist’s destroy Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Othe ...

  2. hdu 4679 Terrorist’s destroy 树形DP

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=4679 题意:给定一颗树,每条边有一个权值w,问切掉哪条边之后,分成的两颗树的较大的直径*切掉边的权值最小? ...

  3. HDU 4679 Terrorist’s destroy

    如果不在最长路的边,那么肯定是w*最长路. 如果在最长路,那么把最长路分成两段,左边树的最长路就是左段+左边点的次短路(不包含最长路上的点的最长路) ,右边同理. 还有就是更新,经过左端点的最长路,不 ...

  4. hdu 4679 Terrorist’s destroy 树的直径+dp

    题意:给你一棵树,每条边都有值W,然后问你去掉一条边,令val = w*max(两颗新树的直径),求val最小值~ 做法,先求树的直径,然后算出直径上每个点的最长枝条长度.这样对于每一条边,假如是枝条 ...

  5. 树形DP 2013多校8(Terrorist’s destroy HDU4679)

    题意: There is a city which is built like a tree.A terrorist wants to destroy the city's roads. But no ...

  6. HDU-4679 Terrorist’s destroy 树形DP,维护

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4679 题意:给一颗树,每个边有一个权值,要你去掉一条边权值w剩下的两颗子树中分别的最长链a,b,使得w ...

  7. hdu 4679 树状dp

    思路:我们其实只需要枚举每条边,求得最小值就行了. 先dfs算出每个节点作为根时,其子树的最长路径,以及进过该节点的最长,次长,第三长路径. 然后在次dfs枚举求出切断某条边,求出这条边的两个端点为子 ...

  8. hdu 4679 (树形DP)

    题意:给一棵树,边的权值都是1,摧毁每条边是有代价的,选择摧毁一条边,把一棵树分成两部分,求出两部分中距离最大的两点的距离,求出距离*代价最小的边,多条的话输出序号最小的. 刚开始理解错题意了,wro ...

  9. HDU 4679 String

    String Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Sub ...

随机推荐

  1. Docker创建Centos踩出来的坑

    屁话不多说,先来一遍正常的流程 1.下载centos镜像 # docker pull centos 2.运行容器,修改镜像 2.1 运行 # docker run -itd --name centos ...

  2. Unity GL 画圆

    Unity下GL没有画圆的函数,只能自己来了. 如果能帮到大家,我也很高兴. 虽然没有画圆的函数,但是能画直线,利用这一点,配合微积分什么的,就可以画出来了.反正就是花很多连在一起的直线,每条直线足够 ...

  3. java打印堆栈信息

    StackTraceElement[] stackElements = new Throwable().getStackTrace(); if(stackElements != null){ for( ...

  4. js和JQuery中offset等属性对比

    HTML: 内容在滚动条下面 <div id="outerDiv"> <div id="myDiv" class="myDiv&qu ...

  5. WebAPI创建

    一.创建Web API 1.Create a New Web API Project创建新的Web API项目 Start by running Visual Studio 2010 and sele ...

  6. C 碎片四 流程控制

    前面介绍了程序中用到的一些基本要素(常量,变量,运算符,表达式),他们是构成程序的基本成分,下面将介绍C语言中流程控制的三种结构:顺序结构.分支结构.循环结构 一.顺序结构 顺序结构的程序设计是最简单 ...

  7. jquery 的extend的方法

    用flot.js  用到了jquery的extend 方法 关于extend方法 我就照手册打一遍,加深一下理解,说实话其实我理解的也不透 extend  用一个或多个其他对象来扩展一个对象,返回被扩 ...

  8. Cloneable接口的作用

    Cloneable接口是一个[标记接口],就是没有任何内容 implements Cloneable表示该对象能被克隆,能使用Object.clone()方法.如果没有implements Clone ...

  9. pat乙级1045

    从左到右扫描时记录扫描到当前下标为止的最大值,如果当前元素大于这个最大值,那么它就大于它左边的所有值.同理,从右到左扫描记录扫描到当前下标为止的最小值,如果当前元素小于这个最大小值,那么它就小于它右边 ...

  10. Android(java)学习笔记89:Bundle和Intent类使用和交互

    1. Bundle 和 Intent:    Bundle只是一个信息的载体 将内部的内容以键值对组织 ,Intent负责Activity之间的交互自己是带有一个Bundle的.Intent.putE ...