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. OO 第三单元总结

    1. JML梳理 根据JML LEVEL 0手册梳理常用条目 1.1 JML 理论基础 \result表达式 : 表示方法返回值 \old( expr )表达式:表示方法执行之前expr表达式取值,若 ...

  2. Flash图表控件FusionCharts调整图表百分比大小

    用户可以为图表的宽度和高度设置百分比值,用来替代绝对的像素值. 以百分比的方式调整图表,首先需要更新HTML代码,如下所示: <div id="chartContainer" ...

  3. Linux、命令ps 各字段意思

    参数: -A :所有的进程均显示出来,与 -e 具有同样的效用: -a : 显示现行终端机下的所有进程,包括其他用户的进程: -u :以用户为主的进程状态 : x :通常与 a 这个参数一起使用,可列 ...

  4. 云中(云厂商)抗DDoS究竟哪家强?

    随着云计算的兴起,大量资源触手可得,这让DDoS攻击的成本断崖般下降,而人们对于互联网服务的可靠性要求又在不断加强,这就使得DDoS攻击所造成的破坏力与日俱增.面对日趋严重的网络安全形势,企业传统的见 ...

  5. PHP与MYSQL结合操作——文章发布系统小项目(实现基本增删查改操作)

    php和mysql在一起几十年了,也是一对老夫老妻了,最近正在对他们的爱情故事进行探讨,并做了一个很简单的小东西——文章发布系统,目的是为了实现mysql对文章的基本增删查改操作 前台展示系统有:文章 ...

  6. 异常:System.InvalidOperationException: This implementation is not part of the Windows Platform FIPS validated cryptographic algorithms 这个实现是不是Windows平台FIPS验证的加密算法。解决方法

    遇见这个问题是在使用了MD5加密算法后报错的,可能的原因如下: 1.FIPS不兼容MD5,此时需要修改注册表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\C ...

  7. java生成excel文档

    要做一个后台自动化,要先预先生成一份文档,以下内容生成了文档 首先下载jxl.jar包,下载地址:http://download.csdn.net/detail/prstaxy/4469935 1.生 ...

  8. hdu-2066 一个人的旅行---模板题

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2066 题目大意: 求到目标点集合中的最短距离 解题思路: dijkstra算法求出每个点到该点的最短 ...

  9. 【洛谷4011】孤岛营救问题(状压SPFA)

    点此看题面 大致题意: 有一个\(N*M\)的四联通迷宫,相邻两个可能互通,可能有一扇门,也可能有一堵墙.对于第\(i\)类的门,你需要有第\(i\)类的钥匙才可以通过.问你从\((1,1)\)到达\ ...

  10. 【BZOJ1433】[ZJOI2009] 假期的宿舍(二分图匹配入门)

    点此看题面 大致题意:有\(n\)个学生,其中一部分是在校学生,一部分不是,而在校学生中一部分回家,一部分不回家,并且我们用一个01矩阵表示学生之间相互认识关系.已知每个学生只能睡自己认识的人的床(当 ...