【编程笔试】美团2021校招笔试-通用编程题第1场(附思路及C++代码)

本文介绍了美团骑手小美的送花路线规划问题,涉及树形结构最短路径计算,以及骑手绩效的两个关键指标:花店到所有客户地址的距离之和与实际行驶路程。同时,讲解了如何计算小美的评分、外卖省钱计划以及代金券消消乐策略,展示了在C++中处理这些问题的算法和思路。
摘要由CSDN通过智能技术生成

练习地址

点此前往练习

小美的送花路线

小美是美团的一名鲜花快递员,鲜花是一种保质期非常短的商品,所以需要尽快送到客户手中,公司对于骑手的一个要求就是要规划送花的线路,使得骑手送完所有订单走的路程尽可能少。

(骑手开始派送时带走了所有需要派送的花,不必每单后返回花店,路程结算是从花店出发,到送完最后一名客户为止,不计算从最后一名客户家回到花店的时间)

公司对于骑手的绩效评价是取决于两个指标,一是从花店到所有客户地址的距离之和,另一个是骑手实际走的路程。

设花店始终位于1号位置,客户共有n-1个,其编号为2~n。令dis(i,j)表示i号位置到j号位置的距离,即分别计算 ∑ i = 2 n d i s ( 1 , i ) \sum_{i=2}^{n}dis(1,i) i=2ndis(1,i), 和骑手实际所走的最短路程。

为了简化问题,我们约束这n个位置构成的是一棵树,即只有n-1条边在其中互相连接,且保证n个点彼此连通。

输入描述:

输出第一行包含一个正整数n,即花店和客户的总数。(1<=n<=30000)接下来有n-1行,每行有三个整数u,v,w,表示在u和v之间存在一条距离为w的道路。(1<=w<=1000)

输出描述:

输出包含两个整数,中间用空格隔开,分别表示花店到所有客户地址的距离之和和骑手实际走的路程。

输入例子1:

5

1 2 3

1 3 1

1 4 2

2 5 1

输出例子1:

10 10

思路:

3
1
2
1
1
2
3
4
5

根据题设,考虑树状结构。求:

sum1:从花店到所有客户地址的距离之和;

sum2:骑手实际走的最短路程,且最后一趟不需再返回。

求sum1:

根据输入的u、v、w,对于任意节点都能写出dp[v]=dp[u]+w,从而得到sum1。

对于例子1来说,sum1+=dp[v]。如dp[5]=dp[2]+1=3+1=4。sum1=3+1+2+4=10。

求sum2:

要求最短路径,根据最后一趟不需返回,可知最后一趟一定是从花店到最远的客户地址处,这部分距离只需计算一次,其余的到其他客户地址的距离需要计算往返路程。因此sum2+=2×w,还要-maxlen,其中maxlen是dp[v]中的最大值。

对于例子1来说,离花店最远的客户地址是5,路程中还途径了客户1。因此,sum2=2×(3+1+2+1)-(3+1)=10。

代码:

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

int main()
{
    int n;
    cin>>n;
    vector<int>dp(n,0);
    int sum1 = 0,maxlen = 0,sum2 = 0;
    int u,v,w;
    for(int i=0;i<n-1;i++){
        cin>>u>>v>>w;
        dp[v] = dp[u]+w;
        sum2 += w*2;
        maxlen = max(dp[v],maxlen);
        sum1 += dp[v];
    }
    cout << sum1 << " " << sum2-maxlen;
}

小美的评分计算器

美团对于商家的评价体系是1-5星评价体系,用户在完成订单之后可以对商家打1/2/3/4/5星,而在客户端上,商家的评级却不一定是整数,而是会显示小数点后的一位。很显然这就需要一个计算器了,小美拥有了一些商户的评价数据,希望可以计算出商家在客户端上显示出的评分。

这个评分的计算非常简单,就是对该商家的所有客户的星级评价做求一个平均,然后去尾法显示小数点后的一位即可,例如平均得分是3.55,则显示的是3.5。例如某商家获得了1-5星评价各一个,则显示的评分是(1+2+3+4+5)/5=3.0。

如果商家没有获得评价,则显示0.0。

输入描述:

输入包含5个整数,依次分别表示商家获得1星到5星的评价数量,每一种评价的数量都不大于1000。

输出描述:

输出仅包含一个保留一位的小数,表示商家在客户端上显示的评级。

输入例子1:

2 2 1 1 2

输出例子1:

2.8

思路:

需注意的点:

①输入的是1星到5星的评价的数量;

②两个整数相除还是整数,需要用强制转换成小数;

③需要考虑输出为0.0的情况。

④不四舍五入的小数去尾的实现:乘整十(一位小数)向下取整再除十,使用fixed和setprecision控制实数部分及小数部分精度。

代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n1,n2,n3,n4,n5;
	cin>>n1>>n2>>n3>>n4>>n5;
	double rate = 0;
	rate = (double)(1*n1+2*n2+3*n3+4*n4+5*n5)/(n1+n2+n3+n4+n5);
	if(n1==0&&n2==0&&n3==0&&n4==0&&n5==0)
	{
		cout<<"0.0";
	}
	else
	{
		cout<<fixed<<setprecision(1)<<floor(rate*10.0)/10.0; 
	}
}

小美的外卖省钱计划

2020年的618不再仅仅是购物节啦,同时也是美团外卖节,小美早早就准备好了各种满减代金券,为了最大程度的“省钱”,当然是选择把这些代金券都用光啦!

这些代金券都有一个使用门槛,即满多少元的订单才可以使用。如果使用一个二元组<x,y>表示一张代金券,即需要满x元才能优惠y元,那么需要注意的是,并不是所有代金券的x都是大于等于y的,良心美团也会推出一些x<y的代金券。如果x<y,例如x=1,y=2,则购买1元商品的情况下无需付款,不会退款给用户。

请问小美如果想用完这些代金券,在保证总付款金额最小的情况下,她最多购买多少钱的外卖呢?

说明:

1.一个订单只能用一张代金券。

2.同时满足总付款金额最少,且购买的外卖价值最高,例如两个优惠完都是1元的外卖,一个原价3元另一个原价4元,则选4元的。

3.由于美团商户很多,所以对于任何一个价格我们都可以找到至少一种商品购买。

输入描述:

输入第一行仅包含一个正整数n,表示小美拥有的代金券数量。(1<=n<=50000)接下来有n行,每行有两个整数x和y,表示一张代金券需要订单金额满x元可以使用,能够优惠y元。(1<=x<=10000,1<=y<=10000)

输出描述:

输出仅包含两个正整数,中间用空格隔开,分别表示小美购买的外卖价值和她的实际付款金额。

输入例子1:

3

5 3

10 5

1 2

输出例子1:

17 7

思路:

求购买的外卖价值sum1和实际付款金额sum2。

根据代金券的x与y的情况分为x>y和x≤y两种情况:

求sum1根据代金券的满金额x之和来求(x>y),而当x≤y时,计算的是y之和。

求sum2根据代金券的优惠价值来算,即x-y之和,这是在x>y的情况下求得的。

代码:

#include<bits/stdc++.h>
using namespace std;

int main()
{
	int n;
	cin>>n;
	int x,y,diff,sum=0;
	int sum1=0,sum2=0;
	for(int i=0;i<n;i++)
	{
		cin>>x>>y;
		if(x>y)
		{
			diff = x-y;
			sum2 += diff;
			sum += x;
		}
		else
		{
			sum1+=y;
		}
	}
	cout<<sum1+sum<<" "<<sum2;
}

小美的代金券要过期啦

外卖节即将过去了,小美还有很代金券没有消费掉,美团面向小美这样的用户推出了一个新的活动,即代金券消消乐活动。系统会把小美的代金券打乱顺序排成一排,小美可以进行任意多次如下操作:

如果存在相邻的两个代金券金额相等,设其面额为x,小美可以使用这两张代金券换一张面额为x+1的代金券,并将其仍放在原来两张券的位置上,每进行一次这样的操作,小美就可以获得1元可以无限期使用的奖励金。

小美觉得奖励金可太香了,因此她想获得尽可能多的奖励金,请问她最多可以获得多少奖励金。

输入描述:

输入第一行仅包含一个正整数n,表示小美拥有的代金券数量。(1<=n<=500)输入第二行包含n个正整数,每个整数x表示一张代金券的面额,同时这也是系统排出的代金券顺序。(1<=x<=100)

输出描述:

输出仅包含一个整数,表示小美最多可以获得的奖励金数量。

输入例子1:

5

1 1 1 1 1

输出例子1:

3

例子说明1:

{1,1,1,1,1}->{1,1,1,2}->{1,2,2}->{1,3}

思路:

观察到例子说明中是从后向前进行消消乐的,因此考虑使用栈结构,将序列元素入栈后,当栈顶元素和序列中元素相等时,将输入的x+1。

代码:

#include<bits/stdc++.h>
using namespace std;
	
int main()
{
	
	int n;
	int x = 0;
	cin>>n;
	int* s = new int[n];
	for(int i=0;i<n;i++)
	{
		cin>>s[i];
	}
	stack<int> nums;
	nums.push(s[0]);
	for(int i=1;i<n;i++)
	{
		while(!nums.empty()&&s[i]==nums.top())
		{
			nums.pop(); 
			s[i]++;
			x++;
		} 
		nums.push(s[i]);
	}
	cout<<x;
}

总结

第一题:

  1. C++万能头文件:#include<bits/stdc++.h>

  2. C++控制输入输出:using namespace std; cin>> cout<<

  3. C++ STL中的vector:顺序容器,封装数组

    1. 头文件:#include<vector>

    2. 创建vector对象:vector<T> vec;

    3. 尾部插入数据:vec.push_back(a);

    4. 使用下标访问数据:cout<<vec[0]<<endl;

    5. 使用迭代器访问数据:

      for(vector<int>::iterator i = vec.begin();i != vec.end(); i++)
          cout<<*i<<endl;
      
    6. 插入数据:vec.insert(vec.begin()+i,a);在第i个元素后面插入a.

    7. 删除数据:vec.erase(vec.begin()+2);删除第3个元素

      vec.erase(vec.begin()+i,vec.end()+j);删除区间[i,j-1];区间从0开始

    8. 向量大小:vec.size();

    9. 清空向量中数据:vec.clear();清空之后,vec.size()为0.

  4. C++ STL中的algorithm

    1. 头文件:#include<algorithm>

    2. 常用函数:

      1. reverse(it,it2):将数组指针在[it,it2)之间的元素或容器的迭代器在[it,it2)范围内的元素进行反转。

      2. sort(begin,end,bool):对数组元素和结构体数组排序;对容器排序只能对vector, string, deque进行。

        bool compare(int a,int b)
        {
            return a>b;
        }
        int main()
        {
            vector<int> vec;
            vec.push_back(3);
            vec.push_back(1);
            vec.push_back(2);
            sort(vec.begin(),vec.end(),compare);
            for(int i=0;i<3;i++){
                cout<<vec[i];
            }
            return 0;
        }
        
      3. swap(a,b):交换a和b。

      4. max(a,b):返回a和b中的较大者。

      5. min(a,b):返回a和b中的较小者。

      6. abs(a):取得a的绝对值。

第二题:

  1. 两个整数相除结果依然是整数,如果要小数结果,使用强制转换。

  2. C++保留小数位数(四舍五入):

    1. setprecision(bits)用于设置精度,控制输出数的位数(有效数字),四舍五入。

    2. setiosflags()用于格式控制:

      1. fixed定点方式显示实数(整数部分),后再辅以setprecision以小数位数显示小数,四舍五入。
      2. showpoint显示小数后的0,后再辅以setprecision以小数位数显示小数,四舍五入。
      cout<<setiosflags(ios::fixed|ios::showpoint)<<setprecision(10)<<pi<<endl;
      >>> 3.1415926000
      
  3. C++小数取整处理方式:

    1. 去尾法:整型接收。
    double x = 2.8;
    int y = x;
    
    1. 向上取整:ceil()函数。
    float x = ceil(2.2);	//3.0
    float y = ceil(3.5);	//4.0
    float z = ceil(-2.8);	//-2.0
    
    1. 向下取整:floor()函数。
    float x = floor(3.8);	//3.0
    float y = floor(4.3);	//4.0
    float z = floor(-3.2);	//-4.0
    
    1. 四舍五入:round函数。
    float x = round(3.4);	//3.0
    float y = round(3.6);	//4.0
    float m = round(-2.3);	//-2.0
    float n = round(-3.9);	//-4.0
    
  4. C++保留小数位数(四舍五入):fixed setprecision() floor() 再依据保留位数乘除整十(一位小数)、整百(两位小数)、整千(三位小数)、整万(四位小数)……

cout<<fixed<<setprecision(1)<<floor(4.875*10)/10<<endl;
>>> 4.8

第三题:

暂无

第四题:

C++ STL中的stack:堆栈容器,后进先出

  1. 头文件:#include<stack>

  2. 创建stack对象:stack<T> sck;

  3. 常用操作:

    1. top():返回一个栈顶元素的引用,类型为 T&。如果栈为空,返回值未定义。
    2. push(const T& obj):可以将对象副本压入栈顶。这是通过调用底层容器的 push_back() 函数完成的。
    3. push(T&& obj):以移动对象的方式将对象压入栈顶。这是通过调用底层容器的有右值引用参数的 push_back() 函数完成的。
    4. pop():弹出栈顶元素。
    5. size():返回栈中元素的个数。
    6. empty():在栈中没有元素的情况下返回 true。
    7. emplace():用传入的参数调用构造函数,在栈顶生成对象。
    8. swap(stack<T> & other_stack):将当前栈中的元素和参数中的元素交换。参数所包含元素的类型必须和当前栈的相同。对于 stack 对象有一个特例化的全局函数 swap() 可以使用。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值