2021.8.12携程笔试第三题:建树游戏DFS
| 2021.8.12攜程筆試 |
- 討論區
在做最后一題的時候把題意看錯了,悔之莫及,故記錄此文引以為戒!
建樹游戲
問題描述
有n個節點和n-1條邊,形成一棵樹,每個節點有一個權值。把其中一條邊刪除就形成了兩棵樹,在兩棵樹之間重新接一條新的邊就可以形成一顆新樹。新樹的權值等于新增邊的兩點權值相乘。
每條邊都可以刪除,且可新加的邊有很多,故可以形成很多新樹,請計算這些新樹的數量;同時對于每一條邊,刪除后可以產生的若干新樹的權值之和也不一定相同,請計算這些權值之和中的最大值。
輸入描述
第一行整數n,表示點的數量,3? n ?100000
第二行n-1個整數,空格隔開,第i個整數ai表示點ai與i之間有一條邊
第三行n個整數,空格隔開,表示各個點的權值。0<權值<10000。
輸出描述
一行,兩個整數,用空格隔開,表示新樹的總數量,以及各點刪除后可以產生的新樹的權值之和的最大值。
樣例輸入
3 2 3 1 2 3樣例輸出
2 3問題分析
首先簡化問題,如果斷開一條邊,能產生多少種新樹呢:答案是這條邊兩端節點數之積減去原來的邊,即兩兩組合。
同時,能產生的所有新樹的權值之和呢:答案這條邊兩端所有權值之積j減去原先連接的邊即可。
那么我們只需DFS一遍,遍歷所有的邊即可。每個子節點對應一顆子樹,將父節點與子節點之間的邊斷開就可以形成兩棵樹,然后更新答案。
問題變形
在讀題的時候沒看到之和,而誤以為是求所有新樹的權值的最大值。即每棵新樹對應一個權值,求所有可能的新樹權值的最大值。
如果是這種題意該如何解答呢,問題相當于任意兩個原本不連接的點的權值之積最大。
這個問題也可以通過DFS來解決。
我們只需找出除父節點之外其余節點的最大值即可,與當前點進行連接。
如何理解呢:
- 首先要明白父節點和當前子節點代表兩顆新樹
- 因為答案中肯定存在兩點相連,并且在DFS的時候任意兩點肯定有遍歷的先后,并且我們需要使得這兩點邊權盡量大,這樣使得乘積盡量大。
- 我們無需同時考慮兩點,我們只需更新遍歷過的所有點除父節點外的最大權值,那么在遍歷當前點的時候,當前點就是被連接的點,當前子節點代表的子樹還未被遍歷。
- 即固定當前點,我們只需找到除父節點外,父節點所代表的子樹的所有權值最大值。
- 父節點所代表的子樹會先被遍歷,如果父節點那邊存在未遍歷的點怎么辦呢,還是原來的問題,兩個點會存在先后遍歷的順序,當我們遍歷到被連接的點的時候,其他可能的點會先被遍歷到
這種類型的題目與POJ3140有些類似
| POI 3140 Contestants Division |
問題描述
給你一棵樹,要求你選擇一條邊進行斷開,使得斷開后兩棵子樹權值和之差最小。
問題分析
這個題解法很簡單,DFS統計子樹權值之和,然后計算差值更新答案。
但是這題坑點很多,首先數據范圍,在long long的數據范圍,而且差值絕對值不能用abs()函數對 long long 取絕對值!應該用llabs(long long )函數原型,或者取負號,求正負最值。
另外一個坑點在于m雖然很大,但是實際一棵樹只與n有關,m是誤導信息,不過內存稍微開大幾倍即可。
const int N=1e5+10; struct Edge {int to,next; }e[N*20]; int n,m,head[N],tot; ll sum,ans,a[N]; void init() {ans=1e15;sum=tot=0;memset(head,-1,sizeof(head)); } void add(int u,int v) {e[tot].to=v,e[tot].next=head[u];head[u]=tot++; } ll dfs(int pre,int u) {ll tmp=a[u];for(int i=head[u];i+1;i=e[i].next){int v=e[i].to;if(v==pre) continue;ll cnt=dfs(u,v);ans=min(ans,llabs(cnt-(sum-cnt))); // ans=min(ans,max(cnt-(sum-cnt),(sum-cnt)-cnt));tmp+=cnt;}return tmp; } int main() {int u,v;int cnt=0;while(~scanf("%d%d",&n,&m)&&(n||m)){init();for(int i=1;i<=n;i++){scanf("%lld",&a[i]);sum+=a[i];}for(int i=0;i<m;i++){scanf("%d%d",&u,&v);add(u,v);add(v,u);}dfs(0,1); // cout<<ans<<endl;printf("Case %d: %lld\n",++cnt,ans);}return 0; }總結
以上是生活随笔為你收集整理的2021.8.12携程笔试第三题:建树游戏DFS的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux安装深度播放器,分享|Ubun
- 下一篇: 一个不错的媒体网页播放器(国外的)