一、题目描述:
鲁大师和他的朋友经常去一家奇怪的餐厅,为什么说奇怪呢,一是餐厅提供的菜品比较奇怪,二是餐厅的付费规则比较奇怪,每个人有不同的折扣上限(单人从总结里折算的最高金额),超过折扣上限的部分原价付费(N个人可以每人出一部分),这次鲁大师和魏然层风以及朋友一共N个人去这家餐厅吃饭,他们点的菜品总金额为T,现在告诉你每个人的折扣率z和折扣上限H,请告诉他们最少需要支付多少钱?
二、输入格式:
输入数据有多组,每组占N+1行,第一行是N和T,接下来N行,每行两个数字z和H(0<N<100)
三、输出格式:
对于每组输入数据,输出一行,对应一个要求的答案。答案向下取整。
四、输入样例:
2 100
0.7 70
0.6 50
3 500
0.6 100
0.8 200
0.7 100
1 100
0.6 100
五、输出样例:
65
390
60
六、解决方法:
(1)思路:
- 最少花费:那一定是先计算打折率最多的,剩下的再依次计算打折率小的。(需要按照打折率从高到低排序)
- 从实际角度可知分两种情况:折扣上限总和>花费总和 或者 折扣上限总和<=花费总和。当>时,表示某一个折扣上限未达到,此时只用 剩下未用折扣的那部分乘以 折扣率即可;当<=时 表示 总折扣上限不包含的那部分钱要原价支付。
【注】:在自定义函数中,sum ,sum1,sum2的类型要是double类型,否则输出结果总是和正确结果差2。
(2)代码实现1:
#include <iostream>
#include <algorithm>
using namespace std;
double compute(double a[][2],int n,int T){
double sum = 0,sum1 = 0,sum2 = 0;
//计算所有人的金额上限和sum1,默认上限不会超过花费的总价格
for(int i = 0;i < n;i++)
sum1 += a[i][1];
//如果所有人折扣的金额上限加起来>T,说明总消费都可以用折扣(折扣多了,即三个人吃饭但两个人的折扣都完全够用了)
//如果所有人折扣的金额上限加起来<=T,说明有一部分要原价付
if(sum1>T){
for(int j=0;j<n-1;j++){
T-=(int)a[j][1]; //一个一个除去折扣,表示剩下的未用折扣的总费用
if(T>0) //如果还有未用折扣的总金额,表示需要用到下一行的折扣
sum+=(a[j][0]*a[j][1]);
int i=j+1; //i总是j的下一行,但i<人数n
//如果当前的折扣金额不到折扣上限,故只计算那部分T即可
if(i<n && T<a[i][1])
sum += (a[i][0]*T);
}
}
else{
for(int r=0;r<n;r++) //计算所有折扣率和折扣金额的乘积
sum2 += (a[r][0]*a[r][1]);
T -= sum1; //总价变为用完折扣上限多出的钱,这部分原价付
sum = sum2+T;
}
return sum;
}
int main()
{
int n=0,T=0;
cin>>n>>T;
double a[100][2];
for(int i =0;i<n;i++){
cin >> a[i][0];
cin >> a[i][1];
}
int sum=0;
//按折扣率大小进行排序,这里冒泡排序
for(int i=0;i<n-1;i++)
for(int j=n-1;j>i;j--)
if(a[j-1][0]>a[j][0]){ //从后往前比较,若前大后小,交换
double temp1=a[j-1][0]; //交换打折率
a[j-1][0]=a[j][0];
a[j][0]=temp1;
double temp2=a[j-1][1]; //交换打折上限
a[j-1][1]=a[j][1];
a[j][1]=temp2;
}
//传入参数
sum = compute(a,n,T);
cout<< sum<<endl;
system("pause");
return 0;
}
(3)代码实现2:结合结构体来实现(也可以定义一个vector来解决)
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
//创建一个person的结构体,包含每个人的打折率z和打折上限h,并定义一个名为 a 的person结构体
struct person{
double z,h;
}a[100+10];
//表示从小到大排序。当打折率相同时,按折扣上限从小到大排序(0.5表示打五折,0.8表示打八折,显然打五折比打八折便宜)
//其实也可以直接 return a.z<b.z
int cmp(const person &a,const person &b){
if(a.z==b.z){
return a.h<b.h;
}
else{
return a.z<b.z;
}
}
int main()
{
int n,t;
while(scanf("%d %d",&n,&t)!=EOF){
for(int i=0;i<n;i++)
{
scanf("%lf %lf",&a[i].z,&a[i].h);
}
//sort函数第三个参数,表示排序方法,默认从小到大排序(如果cmp函数中return a.z>b.z则表示从大到小排序)
sort(a,a+n,cmp);
double sum = 0.0;
for(int i=0;i<n;i++)
{
if(t>=a[i].h){
t=t-a[i].h;
sum+=a[i].z * a[i].h;
}else{
sum+=a[i].z * t;
t=0.0;
break;
}
}
printf("%d\n",(int)sum+t);
}
return 0;
}