poj - 2631 roads in the north:
題目大意:給你一棵樹,求這棵樹的直徑。
樹的直徑:樹中最長的簡單路徑。
簡單路徑:路徑上各點均不重複。
以下證明內容**
這裡給出樹的直徑的證明:
主要是利用了反證法:
假設 s-t這條路徑為樹的直徑,或者稱為樹上的最長路
現有結論,從任意一點u出發搜到的最遠的點一定是s、t中的一點,然後再從這個最遠點開始搜,就可以搜到另乙個最長路的端點,即用兩遍廣搜就可以找出樹的最長路
證明:1.設u為s-t路徑上的一點,結論顯然成立,否則設搜到的最遠點為t則 dis(u,t) >dis(u,s) 且 dis(u,t)>dis(u,t) 則最長路不是s-t了,與假設矛盾
2.設u不為s-t路徑上的點
首先明確,假如u走到了s-t路徑上的一點,那麼接下來的路徑肯定都在s-t上了,而且終點為s或t,在1中已經證明過了
所以現在又有兩種情況了:
1:u走到了s-t路徑上的某點,假設為x,最後肯定走到某個端點,假設是t ,則路徑總長度為dis(u,x)+dis(x,t)
2:u走到最遠點的路徑u-t與s-t無交點,則dis(u-t) >dis(u,x)+dis(x,t);顯然,如果這個式子成立,
則dis(u,t)+dis(s,x)+dis(u,x)>dis(s,x)+dis(x,t)=dis(s,t)最長路不是s-t矛盾
求樹的直徑用2次bfd和2次dfs都可以。
使用優先佇列需要過載結構體(ac):
#include #include #include #include #include using namespace std;
struct node
node(int xi, int sumi)
};struct nod
edge[20005];
vectormp[20005];
priority_queuequ;
int vis[20005] = ;
int main()
qu.push(node(s, 0));
vis[s] = 1;
while(!qu.empty())
}memset(vis, 0, sizeof(vis));
qu.push(node(s, 0));
vis[s] = 1;
while(!qu.empty())
}printf("%d\n", s);
}
另一種思路(可以處理負邊)(樹形dp):
樹的直徑必然是樹上某乙個點開始往下的最長鏈和次長鏈之和。
#include #include #include #include #include #include using namespace std;
struct node
edge[20005];
vectormp[20005];
int dp1[20005] = , dp2[20005] = ;
int vis[20005] = ;
void slove(int u)
return ;
}int main()
vis[s] = 1;
slove(s);
//for(i = 1; i <= 15; i++)cout << i << " " << dp1[i] << " " << dp2[i] << endl;
int ans = dp1[1] + dp2[1];
for(int i = 1; i <= 10000; i++)ans = max(ans, dp1[i] + dp2[i]);
printf("%d\n", ans);
}
《學習筆記》 樹的直徑 Bfs Dfs
樹的直徑為樹上最長的一條路徑 不經過重複節點 也可以看做是樹上最長路。通常的求法 1.兩邊bfs或兩邊dfs 2.樹形dp 端點為根和僅經過根 emmm 蒟蒻表示目前只會第一種qaq。從樹中找出任意一點,求出與他距離最遠的點s,再用同樣的方法求出與s距離最遠的點t,s t即為樹的直徑。bfs 1 i...
樹的直徑與重心學習筆記
此文為完成任務所設,可能不易懂,能看懂就將就著看吧 樹的定義 不存在環且聯通的圖。樹的直徑 樹中的最長鏈 樹的重心 為乙個點,以此點為根,最大子樹的大小最小。樹的直徑求法分兩種 兩次 dfs bfs 與樹形 dp 首先講好理解點的樹形 dp 其實很簡單,每個節點維護子樹到這個點的最長鏈和次長鏈。對於...
樹的直徑 樹的重心與樹的點分治學習筆記
樹的直徑是指樹上的最長簡單路。任選一點w為起點,對樹進行搜尋,找出離w最遠的點u。以u為起點,再進行搜尋,找出離u最遠的點v。則u到v的路徑長度即為樹的直徑。簡單證明 如果w在直徑上,那麼u一定是直徑的乙個端點。反證 若u不是端點,設直徑的兩端為s與t,則dist w,u dist u,t 且dis...