日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

2021.8.12携程笔试第三题:建树游戏DFS

發布時間:2023/12/31 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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一遍,遍歷所有的邊即可。每個子節點對應一顆子樹,將父節點與子節點之間的邊斷開就可以形成兩棵樹,然后更新答案。

#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+10; int n; ll a[N],tot; vector<int>g[N]; ll ans1,ans2; void init() {tot=ans1=ans2=0;a[0]=0;for(int i=1; i<=n; i++)g[i].clear(); } struct node {ll cnt,tmpMax,tmptot; }; node dfs(int pre,int u) // 求所有新樹權值之和的最大值 {long long cnt=1;long long tc=a[u];int len=g[u].size();node tmp;for(int i=0;i<len;i++){int v=g[u][i];if(v==pre)continue;tmp = dfs(u,v);cnt+=tmp.cnt;tc+=tmp.tmptot;ans1+=(n-tmp.cnt)*tmp.cnt-1;ans2=max(ans2,(tot-tmp.tmptot)*tmp.tmptot-a[u]*a[v]); // cout<<v<<" "<<tmp.tmptot<<endl;}tmp.cnt=cnt,tmp.tmptot=tc;return tmp; } int main() {int x;while(~scanf("%d",&n)){init();for(int i=1; i<n; i++){scanf("%d",&x);g[i].push_back(x);g[x].push_back(i);}for(int i=1; i<=n; i++){scanf("%lld",&a[i]);tot+=a[i];}dfs(0,1);cout<<ans1<<" "<<ans2<<endl;;}return 0; }/* 3 2 3 1 2 3 4 4 1 2 1 1 2 3*/
問題變形

在讀題的時候沒看到之和,而誤以為是求所有新樹的權值的最大值。即每棵新樹對應一個權值,求所有可能的新樹權值的最大值。
如果是這種題意該如何解答呢,問題相當于任意兩個原本不連接的點的權值之積最大。
這個問題也可以通過DFS來解決。
我們只需找出除父節點之外其余節點的最大值即可,與當前點進行連接。
如何理解呢:

  • 首先要明白父節點和當前子節點代表兩顆新樹
  • 因為答案中肯定存在兩點相連,并且在DFS的時候任意兩點肯定有遍歷的先后,并且我們需要使得這兩點邊權盡量大,這樣使得乘積盡量大。
  • 我們無需同時考慮兩點,我們只需更新遍歷過的所有點除父節點外的最大權值,那么在遍歷當前點的時候,當前點就是被連接的點,當前子節點代表的子樹還未被遍歷。
  • 即固定當前點,我們只需找到除父節點外,父節點所代表的子樹的所有權值最大值。
  • 父節點所代表的子樹會先被遍歷,如果父節點那邊存在未遍歷的點怎么辦呢,還是原來的問題,兩個點會存在先后遍歷的順序,當我們遍歷到被連接的點的時候,其他可能的點會先被遍歷到
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+10; int n; ll a[N],tot; vector<int>g[N]; ll ans1,ans2; void init() {tot=ans1=ans2=0;a[0]=0;for(int i=1; i<=n; i++)g[i].clear(); } struct node {ll cnt,tmpMax,tmptot; }; node dfs1(int pre,int u,ll preMax) // 求所有新樹權值的最大值 {int len=g[u].size();long long cnt=1;node tmp;for(int i=0; i<len; i++){int v=g[u][i];if(v==pre)continue;ans2=max(ans2,preMax*a[v]);tmp=dfs1(u,v,max(preMax,a[u]));ans1+=(tmp.cnt*(n-tmp.cnt))-1;cnt+=tmp.cnt;preMax=max(preMax,tmp.tmpMax); // 其他子樹下的最值}tmp.cnt=cnt;tmp.tmpMax=max(preMax,a[u]);// cout<<u<<" "<<cnt<<endl;return tmp; } int main() {int x;while(~scanf("%d",&n)){init();for(int i=1; i<n; i++){scanf("%d",&x);g[i].push_back(x);g[x].push_back(i);}for(int i=1; i<=n; i++){scanf("%lld",&a[i]);tot+=a[i];}dfs(0,1);cout<<ans1<<" "<<ans2<<endl;;}return 0; }/* 3 2 3 1 2 3 4 4 1 2 1 1 2 3 */

這種類型的題目與POJ3140有些類似

POI 3140 Contestants Division

問題描述

給你一棵樹,要求你選擇一條邊進行斷開,使得斷開后兩棵子樹權值和之差最小。

問題分析

這個題解法很簡單,DFS統計子樹權值之和,然后計算差值更新答案。
但是這題坑點很多,首先數據范圍,在long long的數據范圍,而且差值絕對值不能用abs()函數對 long long 取絕對值!應該用llabs(long long )函數原型,或者取負號,求正負最值。

整型類型變量(整數)取絕對值: int abs( int x ); long int labs( long x ); long long int llabs( long long x );浮點類型變量(小數)取絕對值: double( double x ); float fabsf(float x); long double fabsl( long double x) ; 相關頭文件: #include <stdlib.h> // #include <cstdlib> #include <math.h> // #include <cmath>

另外一個坑點在于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的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 久久国产精品精品国产 | 日韩av一区在线 | 美女网站污 | 性欧美videos另类hd | 在线观看黄色免费视频 | 欧美人吸奶水吃奶水 | 区一区二区三 | 亚洲国产精品久久久久 | 亚洲精品国产精品国自产观看 | 老色驴综合网 | 国产一区不卡在线观看 | www.欧美在线| 男人舔女人下部高潮全视频 | 色诱视频在线观看 | 国产剧情自拍 | 亚洲国产日韩一区二区 | 亚洲午夜久久久久久久久久久 | 91精品推荐 | 深田咏美在线x99av | 性色网站| 国产在线观看中文字幕 | 一级特黄色片 | 风流僵尸艳片a级 | xxx国产精品 | 久久久.com | 国产真人无码作爱视频免费 | 亚洲一二三四在线观看 | av不卡在线免费观看 | 久操免费在线视频 | 黄色av大全 | 日日夜夜噜噜噜 | 成年人看片网站 | 日韩不卡中文字幕 | 少妇影院在线观看 | 成人黄色小视频在线观看 | 视频成人免费 | 大乳丰满人妻中文字幕日本 | 亚洲综合狠狠 | 天堂福利在线 | 中文日韩在线 | 97超碰网| 亚洲人成人一区二区在线观看 | 国产做爰免费观看视频 | 亚洲色图3p| 少妇av片| 亚洲欧美系列 | 欧美视频第一页 | 天堂岛av | 成人做受黄大片 | 国产精品一国产精品 | 奇米四色网 | 久久人| 国产中文字幕免费 | 国产原创av在线 | 一级黄色在线视频 | 久久国产精品久久久久久电车 | 欧美mv日韩mv国产 | 日韩第1页| 国产精品乱码一区二区三区 | 欧美在线免费 | 日韩色一区 | 国产精品一区二区视频 | 精品深夜av无码一区二区老年 | 豆花av| 日本精品视频在线 | 国产资源在线视频 | 少妇无内裤下蹲露大唇视频 | 免费网站在线观看人数在哪动漫 | 国产成人在线看 | 欧美成人免费观看视频 | xx久久| 免费在线国产 | 久久久久久九九九九 | 亚洲一区不卡 | 日韩国产高清在线 | 日韩久久精品一区二区 | 极品丰满少妇 | 91新视频| 狠狠干一区| 欧美性猛交一区二区三区精品 | 免费成人精品 | 91爱看| 一级黄av| 久久国产加勒比精品无码 | 依人成人综合网 | 99热这里只有精品5 国产精品伦子伦免费视频 精品一二三 | 欧美少妇一区二区三区 | 日韩av在线资源 | 国产精久久一区二区三区 | 欧美少妇诱惑 | 一级免费在线观看 | 伊人青青操 | 秋霞毛片少妇激情免费 | 激情久久五月 | 老熟妻内射精品一区 | 欧美亚洲天堂网 | 久久91久久 | 欧美性猛交xxxx久久久 | 国产在线一二 |