http://acm.hdu.edu.cn/showproblem.php?pid=4679
Terrorist’s destroy
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 268 Accepted Submission(s): 74
Note that the length of each road is one.
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)
哎。。。又是赛后5分钟AC啊。。。伤不起。。。
思路,最后才想到解法,感觉有点麻烦,调试了半天。。。还是代码能力不足的结果。
我们队的方法是首先先设节点1为根节点,然后设len[i]表示以i节点为根的子树中的最长链,设dep[i]表示以i为根节点的子树中
距离i最远的节点到i的距离。设maxf[i]表示i的非子节点集中距离i的最远的点到i的距离。
这三个值可以用普通的树状DP解决,这里就不多说了。
接下来我们dfs从根节点遍历整棵树,当我们经过一个节点时,我们枚举它与它的子节点间的边,计算删除这条边所需的代价,
我们设当前经过的点为u,它的子节点为v,设边v--u的权值为val,删除边u--v后与v相连的那部分子树的最长链显然为len[v],现在关键是求与u相连的那部分子树的最长链,现在我们假设在dfs遍历到u时已经将u之上且不与u相连的最长链的长度求出,设为ma,这个可以由dfs从它的父节点传下来(具体看代码实现),那么现在的任务就是求与u相连或者u其他子节点(不包括v)的最长链的长度,再和ma比较。便可得到与u相连的子树中的最长链。首先u的其他子节点的最长链就是len[x](x是u的子节点且x不为v),然后求与u相连的最长链,我们可以求u的子节点中dep[x]+1最大的两个(不包括v),设为m1,m2,然后再加上maxf[u],这三个值里面去最大的两个相加即为所求。这样我们就得到了与u相连的子树中的最长链,同时我们可以将这个值传到节点v中,同节点u中的ma。这样我们就可以通过枚举,得到所要求的答案。
可能说的有些复杂,但是实现更加复杂。。。。除了上面所讲的外,还需要注意些细节,具体实现还是参考代码吧。
另外注意dfs会爆栈的,可以用#pragma comment(linker, "/STACK:1024000000,1024000000") 。
代码如下:
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#define maxn 100010
#define ll long long
using namespace std;
int len[maxn],dep[maxn],maxf[maxn];
struct edge
{
int to;
int next;
int w,id;
}e[maxn<<1];
int box[maxn],cnt=0;
void init(int n)
{
memset(box,-1,sizeof(int)*n);
memset(len,0,sizeof(int)*n);
memset(dep,0,sizeof(int)*n);
memset(maxf,0,sizeof(int)*n);
cnt=0;
}
void add(int from,int to,int w,int id)
{
e[cnt].to=to;
e[cnt].w=w;
e[cnt].id=id;
e[cnt].next=box[from];
box[from]=cnt++;
}
ll Max;
int ansid;
void dfs1(int now,int fa)
{
int t,v;
int m1=0,m2=0;
for(t=box[now];t+1;t=e[t].next)
{
v=e[t].to;
if(v!=fa)
{
dfs1(v,now);
dep[now]=max(dep[now],dep[v]+1);
len[now]=max(len[now],len[v]);
if(dep[v]+1>=m1)
m2=m1,m1=dep[v]+1;
else if(dep[v]+1>=m2)
m2=dep[v]+1;
}
}
len[now]=max(len[now],m1+m2);
}
void dfs2(int now,int fa)
{
int t,v;
int m1=0,id1=0,m2=0,id2=0;
for(t=box[now];t+1;t=e[t].next)
{
v=e[t].to;
if(v!=fa)
{
if(dep[v]+1>=m1)
{
m2=m1;
id2=id1;
m1=dep[v]+1;
id1=v;
}
else if(dep[v]+1>=m2)
{
m2=dep[v]+1;
id2=v;
}
}
}
for(t=box[now];t+1;t=e[t].next)
{
v=e[t].to;
if(v!=fa)
{
if(id1==v)
{
maxf[v]=max(maxf[now],m2)+1;
dfs2(v,now);
}
else
{
maxf[v]=max(maxf[now],m1)+1;
dfs2(v,now);
}
}
}
}
void dfs3(int now,int fa,int ma)
{
int t,v;
int m1=0,m2=0,m3=0,id1=0,id2=0;
for(t=box[now];t+1;t=e[t].next)
{
v=e[t].to;
if(v!=fa)
{
if(dep[v]+1>=m1)
m3=m2,m2=m1,id2=id1,m1=dep[v]+1,id1=v;
else if(dep[v]+1>=m2)
m3=m2,m2=dep[v]+1,id2=v;
else if(dep[v]+1>=m3)
m3=v;
}
}
int n1=0,pid1=0,n2=0;
for(t=box[now];t+1;t=e[t].next)
{
v=e[t].to;
if(v!=fa)
{
if(len[v]>=n1)
n2=n1,n1=len[v],pid1=v;
else if(len[v]>=n2)
n2=len[v];
}
}
for(t=box[now];t+1;t=e[t].next)
{
v=e[t].to;
if(v!=fa)
{
int ans=ma;
if(v==id1)
ans=max(ans,max(m2+m3,m2+maxf[now]));
else if(v==id2)
ans=max(ans,max(m1+m3,m1+maxf[now]));
else
ans=max(ans,max(m1+m2,m1+maxf[now]));
if(v==pid1)
ans=max(ans,n2);
else
ans=max(ans,n1);
ll tmp=(ll)max(ans,len[v]);
if(tmp*e[t].w<Max)
{
Max=tmp*e[t].w;
ansid=e[t].id;
}
else if(tmp*e[t].w==Max&&ansid>e[t].id)
ansid=e[t].id;
dfs3(v,now,ans);
}
}
}
int main()
{
// freopen("dd.txt","r",stdin);
int ncase,T=0;
scanf("%d",&ncase);
while(ncase--)
{
int n,i,x,y,w;
scanf("%d",&n);
init(n+1);
for(i=1;i<n;i++)
{
scanf("%d%d%d",&x,&y,&w);
add(x,y,w,i);
add(y,x,w,i);
}
ansid=0;
Max=(1LL<<62);
dfs1(1,0);
dfs2(1,0);
dfs3(1,0,0);
printf("Case #%d: %d\n",++T,ansid);
}
return 0;
}