华为2023暑期笔试(1-2)

题目:

  主办方设计了一个获取食物的游戏,游戏的地图由N个方格组成,每个方格上至多2个传送门,通过传送门可将参与者传送至指定的其它方格。同时,每个方格上标注了三个数字:

  1. 第一个数字id:代表方格的编号,从0到 N-1,每个方格各不相同;
  2. 第二个数字parent-id: 代表从编号为parent-id的方格可以通过传送门传送到当前方格(-1则表示没有任何方格可以通过传送门传送到此方格,这样的方格在地图中有且仅有一个) ;
  3. 第三个数字value: 取值在[-100,100]的整数值,正整数代表与者得到相应数值单位的食物,负整数代表失去相应数值单位的食物(参与者可能存在临时持有食物为负数的情况),0则代表无变化。
    此外,地图设计时保证了参与者不可能到达相同的方格两次,并且至少有一个方格的value是正整数。

  游戏开始后,参与者任意选择一个方格作为出发点,当遇到下列情况之退出游戏。请计算参与者退出游戏后,最多可以获得多少单位的食物。

  1. 参与者当前所处的方格无传送门;
  2. 参与者在任意方格上主动宣布退出游戏

输入:

第一行: 方块个数N (N <10000)
接下来输入N行(id<Nparent-id < N,),每行记录了相应方格上标注的3个数字,即id (0 <= id < 10000) 、parent-id (0 <= parent-id < 10000和value (-100<= value <= 100),例如:

3
0 -1 3
1 0 1
2 0 2

输出:

参与者最多可以获得的食物单位数,例如5,参与者从方格0出发,通过传送门到达方格2,一共可以获得3+25个单位食物,此时得到食物最多

样例:

输入:
7
0 1 8
1 -1 -2
2 1 9
4 0 -2
5 4 3
3 0 -3
6 2 -3
输出:9

解释:参与者从方格0出发,通过传送门到达方格4,再通过传送门到达方格5,一共获得8+(-2) +3=9个单位食物,得到食物最多,或者与者在游戏开始时处于方格2,直接主动宣布退出游戏,也可以获得9个单位食物。

思路:
这题的本质显然是树搜索问题。建模后用深度优先搜索(DFS) 算法解决。难点在于如何建模。由题意可得,不会经过一个点两次则图中必然没有环,又由于只有一个节点的父亲节点为空(也即-1), 则必然是一棵树。将dfs的含义定义为以从树的根节点能获得的最大的物品价值,在求解这个问题时会遍历所有树上的节点相当于枚举了以任意节点为起点获得的最大值,因此在每个节点return前对最终答案进行更新即可。

代码:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

int dfs(int id, vector<vector<int>> &G, vector<int> &v, vector<int>&a) {   //由于需要记录每一个节点向下的数据,按引用传递a以便修改
	int idMost = 0;
	for (int j : G[id]) {
		idMost = max(dfs(j, G, v, a), idMost);
	}
	a[id] = v[id] + idMost;
	return a[id];
}

int main() {
	int N;							//方块个数
	cin >> N;
	vector<vector<int>> G(N);		//G[i]是编号为i的节点的子节点(i方块所能进入的方块)
	vector<int> v(N);				//v[i]是第i个方块的value
	int root;						//记录作为根节点的方块编号
	for (int i = 0; i < N; i++) {	
		int id, parent_id, value;
		cin >> id >> parent_id >> value;
		v[id] = value;
		if (parent_id == -1) { root = id; } //更新root
		else G[parent_id].push_back(id);	//parent_id节点的所有子节点
	}
	vector<int> a(N);						//f[i]表示以节点i为初始位置遍历时的最大路径加权
	dfs(root,G,v,a);					//dfs搜索
	auto maxPosition = max_element(a.begin(), a.end());   // 返回的是最大值迭代器所在的位置
	cout << *maxPosition << endl;
	return 0;
}

简化为lamda函数形式:

#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>
using namespace std;


int main() {
	int N;							//方块个数
	cin >> N;
	vector<vector<int>> G(N);		//G[i]是编号为i的节点的子节点(i方块所能进入的方块)
	vector<int> v(N);				//v[i]是第i个方块的value
	int root;						//记录作为根节点的方块编号
	for (int i = 0; i < N; i++) {	
		int id, parent_id, value;
		cin >> id >> parent_id >> value;
		v[id] = value;
		if (parent_id == -1) { root = id; } //更新root
		else G[parent_id].push_back(id);	//parent_id节点的所有子节点
	}
	vector<int> a(N);						//f[i]表示以节点i为初始位置遍历时的最大路径加权

	function<int(int)> dfs = [&](int i) {
		int valMore = 0;
		for (int j : G[i]) valMore = max(dfs(j), valMore);
		a[i] = v[i] + valMore;
		return a[i];
	};
	dfs(root);					//dfs搜索,注意需要记录每一个节点向下的数据
	auto maxPosition = max_element(a.begin(), a.end());   // 返回的是最大值迭代器所在的位置
	cout << *maxPosition << endl;
	return 0;
}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值