练习地址
小美的送花路线
小美是美团的一名鲜花快递员,鲜花是一种保质期非常短的商品,所以需要尽快送到客户手中,公司对于骑手的一个要求就是要规划送花的线路,使得骑手送完所有订单走的路程尽可能少。
(骑手开始派送时带走了所有需要派送的花,不必每单后返回花店,路程结算是从花店出发,到送完最后一名客户为止,不计算从最后一名客户家回到花店的时间)
公司对于骑手的绩效评价是取决于两个指标,一是从花店到所有客户地址的距离之和,另一个是骑手实际走的路程。
设花店始终位于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=2∑ndis(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
思路:
根据题设,考虑树状结构。求:
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;
}
总结
第一题:
-
C++万能头文件:
#include<bits/stdc++.h>
-
C++控制输入输出:
using namespace std;
cin>>
cout<<
-
C++ STL中的
vector
:顺序容器,封装数组-
头文件:
#include<vector>
-
创建vector对象:
vector<T> vec;
-
尾部插入数据:
vec.push_back(a);
-
使用下标访问数据:
cout<<vec[0]<<endl;
-
使用迭代器访问数据:
for(vector<int>::iterator i = vec.begin();i != vec.end(); i++) cout<<*i<<endl;
-
插入数据:
vec.insert(vec.begin()+i,a);
在第i个元素后面插入a. -
删除数据:
vec.erase(vec.begin()+2);
删除第3个元素
vec.erase(vec.begin()+i,vec.end()+j);
删除区间[i,j-1];区间从0开始 -
向量大小:
vec.size();
-
清空向量中数据:
vec.clear();
清空之后,vec.size()
为0.
-
-
C++ STL中的
algorithm
:-
头文件:
#include<algorithm>
-
常用函数:
-
reverse(it,it2)
:将数组指针在[it,it2)之间的元素或容器的迭代器在[it,it2)范围内的元素进行反转。 -
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; }
-
swap(a,b)
:交换a和b。 -
max(a,b)
:返回a和b中的较大者。 -
min(a,b)
:返回a和b中的较小者。 -
abs(a)
:取得a的绝对值。
-
-
第二题:
-
两个整数相除结果依然是整数,如果要小数结果,使用强制转换。
-
C++保留小数位数(四舍五入):
-
setprecision(bits)
用于设置精度,控制输出数的位数(有效数字),四舍五入。 -
setiosflags()
用于格式控制:fixed
定点方式显示实数(整数部分),后再辅以setprecision
以小数位数显示小数,四舍五入。showpoint
显示小数后的0,后再辅以setprecision
以小数位数显示小数,四舍五入。
cout<<setiosflags(ios::fixed|ios::showpoint)<<setprecision(10)<<pi<<endl; >>> 3.1415926000
-
-
C++小数取整处理方式:
- 去尾法:整型接收。
double x = 2.8; int y = x;
- 向上取整:
ceil()
函数。
float x = ceil(2.2); //3.0 float y = ceil(3.5); //4.0 float z = ceil(-2.8); //-2.0
- 向下取整:
floor()
函数。
float x = floor(3.8); //3.0 float y = floor(4.3); //4.0 float z = floor(-3.2); //-4.0
- 四舍五入:
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
-
C++保留小数位数(四舍五入):
fixed
setprecision()
floor()
再依据保留位数乘除整十(一位小数)、整百(两位小数)、整千(三位小数)、整万(四位小数)……
cout<<fixed<<setprecision(1)<<floor(4.875*10)/10<<endl;
>>> 4.8
第三题:
暂无
第四题:
C++ STL中的stack
:堆栈容器,后进先出
-
头文件:
#include<stack>
-
创建stack对象:
stack<T> sck;
-
常用操作:
top()
:返回一个栈顶元素的引用,类型为 T&。如果栈为空,返回值未定义。push(const T& obj)
:可以将对象副本压入栈顶。这是通过调用底层容器的 push_back() 函数完成的。push(T&& obj)
:以移动对象的方式将对象压入栈顶。这是通过调用底层容器的有右值引用参数的 push_back() 函数完成的。pop()
:弹出栈顶元素。size()
:返回栈中元素的个数。empty()
:在栈中没有元素的情况下返回 true。emplace()
:用传入的参数调用构造函数,在栈顶生成对象。swap(stack<T> & other_stack)
:将当前栈中的元素和参数中的元素交换。参数所包含元素的类型必须和当前栈的相同。对于 stack 对象有一个特例化的全局函数 swap() 可以使用。