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相关推荐

  1. 2021 8.8拼多多笔试第三题解答

    第三题输出括号匹配  输入包含 "( ) L R D " 题目以后补充.... import java.util.Arrays; import java.util.Scanner; ...

  2. 携程android开发面试题,2017携程笔试题目

    携程是我国著名的旅游为主的网站,想进入携程工作吗?小编为大家整理了2017携程笔试题目,欢迎阅读参考! 2017携程Web前端实习生招聘笔试题 考察encodeURI encodeURI(), dec ...

  3. 2018年携程笔试分享

    晚上参加了携程产品岗的笔试,笔试时间一共一个半小时:20道单选题加3道主观题:单选题总体来说比较简单,几道产品经理基本问题,基本上去牛客网上刷一遍,就没什么问题了....下面重点说一下主观题: 1.为 ...

  4. RN开发实践——仿携程App(三)

    文章最后附上源码地址 上一片博客链接RN开发实践--仿携程App(二) 实现首页中间的内容栏 今天实现首页中间的内容栏,原效果如下: 红框就是今天需要实现的内容 这里可以拆解成四个部分,每个部分都是由 ...

  5. 携程笔试2020/04/01

    记录三道编程题 第一题 求最小客服人数 时间限制:C/C++语言 1000MS:其他语言 3000MS 内存限制:C/C++语言 65536KB:其他语言 589824KB 题目描述: 携程呼叫中心7 ...

  6. 携程2019校招编程题(3)

    携程今年的机试题为20道选择+3编程 由于今天最后提交时第三题编程未通过,交卷之后想出来的解法这里记录一下. import java.util.ArrayList; import java.util. ...

  7. poj1182 and 携程预赛2第一题 带权并查集

    题意:       动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A.  现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底 ...

  8. 第12届蓝桥杯 第三题:《卡片》

    第三题:<卡片> 题目大意 本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可. 解题思路 首先建立一个map映射,将0–9 每个卡片各有2021个存入map: Has ...

  9. 携程笔试(惨败经历)第一题 leetcode 253

    刚开始生怕题做不完,选择题听说去年是15分钟20题,一顿乱选. 第一道选择题 树的前序遍历35421,中序遍历25431, 后序遍历应该是....? 这道题是不是有点问题,没敢仔细看就选了.... 编 ...

最新文章

  1. 经典C语言程序100例之三四
  2. mac下搭建lua环境
  3. 10个实用的机器学习建议
  4. 内部属性 聚合_光的本质(用粒子性解释光的所有属性,颜色,介质内速度改变等)...
  5. 同时对view延时执行两个动画时候的现象
  6. AlgorithmMan,一套免费的算法演示神器(开源动画演示版)
  7. php session 为空,ThinkPHP_session问题_dump显示session为空
  8. JavaScript语法详解:运算符和表达式
  9. 平民级NER︱pycrfsuite的介绍与应用
  10. Matlab rand randn randint
  11. Linux下配置安装NFS
  12. Asp.net MVC3.0 入门指南 4 模型 Model
  13. Java实现人脸识别
  14. 24种不同的ITF条形码字体Interleaved 2 of 5 Barcode Font Advantage Package
  15. 51单片机汇编学习笔记8——中断
  16. 企业网站建设为什么要定制开发?
  17. liveness探测mysql_Kubernetes 服务中 Liveness 和 Readiness 探测
  18. C语言之CoCo去过的城市
  19. makefile写法整理
  20. 接入层-汇聚层组网设计配置案例——双归上行-负载

热门文章

  1. ACM比赛中常见的错误
  2. 汽车之家配置参数抓取
  3. 微软:这个AI应用能帮助视障儿童找到社交自信
  4. 使用小米手机NFC功能充值交通卡
  5. M1芯片Macbook虚拟机安装centos7
  6. 服务器配置service文件实现jar包自启功能
  7. keil MDK 新建项目教程
  8. 微软Office Plus吊打WPS Office?不一定,WPS未来被它“拿捏”了
  9. mod公式的计算法则
  10. 最佳工程实践—思维利器OmniGraffle