糾結的問題。做了兩天,還是在拜讀大牛代碼的情況下ac的。好好謝謝總結吧。
諸位大牛的思路是兩次dfs。前提:建樹的時候按無向邊從上往下建。第一次dfs是搜出一個根結點到其他結點的最長路徑和次長路徑(次長路徑不是最長路徑的子路徑,也就是說不在同一條路上。)
一個結點到其他結點的最長路徑怎麼得到?1、可能是從這個結點往下取到最長路徑。2、可能是從這個結點的父結點上選去另一條路徑。
當情況一時:第一次dfs所得的最長路徑就是要求的結果。當情況二時:第一次dfs所得的次長路徑就是所求結果。
另外,因為是無向邊建樹,所以第一次dfs從下往上搜,第二次dfs從上往下搜。
具體實現:定義dp[i]表示i到其他結點的最長路徑。 f[i]表示從i結點到他的子結點的最長路徑 l[i]表示i到其子結點的次長路徑。 dir[i]表示最長路徑所在的方向,防止最長路徑跟次長路徑重複。
核心代碼:
void dfs_0(int r) {
if(f[r]) return ;
int len = g[r].size();
if(len == 0) return ;
int i, max = -1, flag = -1, flag1 = -1, c;
for(i = 0; i < len; i++) {
c = g[r][i].c;
dfs_0(c);
if(f[c] + g[r][i].val > max) {
max = f[c] + g[r][i].val;
flag = i;
}
}
f[r] = max;
dir[r] = flag;
max = -1;
for(i = 0; i < len; i++) {
c = g[r][i].c;
if(f[c] + g[r][i].val > max && i != flag) {
max = f[c] + g[r][i].val;
flag1 = i;
}
}
if(flag1 != -1) l[r] = max;
}
void dfs_1(int r) {
int i, len, c;
len = g[r].size();
for(i = 0; i < len; i++) {
c = g[r][i].c;
if(i == dir[r])
dp[c] = max(dp[r], l[r]) + g[r][i].val;
else
dp[c] = max(dp[r], f[r]) + g[r][i].val;
dfs_1(c);
}
}
ps:因為可能出現整顆樹只有一條邊的情況,所以輸出結果時取f[i] 和dp[i]的最大。