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;
}