牛客程式設計巔峰賽:經過直徑的點(樹的直徑升級版)
阿新 • • 發佈:2020-12-12
技術標籤:圖論
連結:https://ac.nowcoder.com/acm/contest/9753/C
來源:牛客網
題目描述
牛牛有一棵n個點的無權無根樹,他想知道有多少個點在樹的直徑上,你可以幫幫他嗎?
注意:樹的直徑可能不止一條。
示例1
輸入
3,[1,2],[2,3]
返回值
3
說明
直徑為1−2−3,三個節點均在直徑上,故答案為3。直徑為1-2-3,三個節點均在直徑上,故答案為3。直徑為1−2−3,三個節點均在直徑上,故答案為3。
備註:
2≤n≤1e5
思路:
【錯誤想法及程式碼】這道題讓我卡了整整一天,我之前的思路是通過兩次dfs找到樹的直徑長度以及直徑的某一個端點【不懂樹的直徑的求法可以參考我這篇 部落格】。然後從某一個端點出發進行dfs並記錄路徑長度以及之後最多能走多深,如果這兩個值的和等於樹的直徑,則這個點就一定是直徑上的點,具體程式碼如下:
class Solution { public: /** * 程式碼中的類名、方法名、引數名已經指定,請勿修改,直接返回方法規定的值即可 * * @param n int整型 節點個數 * @param u int整型vector * @param v int整型vector * @return int整型 */ int ans,mxR; int depth[100005]; vector<int> edges[100005]; int dfs1(int u,int f,int now){ int res=0; int size=edges[u].size(); for(int i=0;i<size;i++){ int v=edges[u][i]; if(v==f) continue; dfs1(v,u,now+1); res=max(res,depth[v]); } if(res+now==mxR) ans++; return depth[u]=res+1; } void dfs(int u,int f){ depth[u]=depth[f]+1; int size=edges[u].size(); for(int i=0;i<size;i++){ int v=edges[u][i]; if(v==f) continue; dfs(v,u); } } int PointsOnDiameter(int n, vector<int>& u, vector<int>& v) { // write code here ans=mxR=0; int len=u.size(); for(int i=0;i<len;i++){ edges[u[i]].push_back(v[i]); edges[v[i]].push_back(u[i]); } memset(depth, 0, sizeof(depth)); dfs(1,0); int start=1; for(int i=1;i<=n;i++) if(depth[i]>depth[start]) start=i; dfs(start,0); for(int i=1;i<=n;i++) mxR=max(mxR,depth[i]); memset(depth, 0, sizeof(depth)); dfs1(start,0,1); return ans; } };
然而只能過91%的樣例,卡了一晚上不知道錯在什麼地方【最坑的是發現比賽中許多人竟然用這種方法過了,可能後期增加資料了,但比賽沒有重判!】
睡了個午覺突然發現了一個卡掉我方法的樣例,其示意圖如下:
按道理說所有點的都在直徑上的,然而我的方法一定會遺漏一個點!【這點留給讀者想】
【AC】進一步改善程式碼,我們從直徑的一個端點走到直徑的中間,然後從中間為起點進行dfs,並找到所有能走到深度為直徑的二分之一的點,並統計數量即可。
class Solution { public: /** * 程式碼中的類名、方法名、引數名已經指定,請勿修改,直接返回方法規定的值即可 * * @param n int整型 節點個數 * @param u int整型vector * @param v int整型vector * @return int整型 */ int depth[100005]; int f[100005],g[100005]; vector<int> edges[100005]; void dfs(int u,int fa){ depth[u]=depth[fa]+1; f[u]=fa; g[u]=depth[u]; int size=edges[u].size(); for(int i=0;i<size;i++){ int v=edges[u][i]; if(v==fa) continue; dfs(v,u); g[u]=max(g[u], g[v]); } } int PointsOnDiameter(int n, vector<int>& u, vector<int>& v) { // write code here int ans=0; for(int i=0;i<n-1;i++){ edges[u[i]].push_back(v[i]); edges[v[i]].push_back(u[i]); } dfs(1,0); int start=1; for(int i=1;i<=n;i++) if(depth[i]>depth[start]) start=i; dfs(start,0); for(int i=1;i<=n;i++) if(depth[i]>depth[start]) start=i; int d=depth[start]; if(d%2==0){ for(int i=1;i<d/2;i++) start=f[start]; depth[f[start]]=0; dfs(start,f[start]); depth[start]=0; dfs(f[start],start); for(int i=1;i<=n;i++) if(g[i]==d/2) ans++; } else{ for(int i=1;i<=d/2;i++) start=f[start]; dfs(start,0); for(int i=1;i<=n;i++) if(g[i]==d/2+1) ans++; } return ans; } };