这就是问题所在。
一群学生是每年到不同地点旅行的俱乐部的成员。他们过去的目的地包括印第安纳波利斯,凤凰城,纳什维尔,费城,圣何塞和亚特兰大。今年春天,他们计划去埃因霍温旅行。
该小组事先同意平均分摊费用,但分摊每项费用并不实际。因此,团体中的个人支付特定的费用,例如餐饮,酒店,出租车和机票。旅行结束后,每个学生的费用都计算在内,并且交换金钱,以便每个学生的净费用相同,在1美分以内。在过去,这种货币兑换既乏味又费时。你的工作是从费用清单中计算必须转手的最低金额,以便使所有学生均等(在1美分以内)。成本。
标准输入将包含多次旅行的信息。每次旅行都包含一个包含正整数n的行,表示旅行中的学生人数。接下来是n行输入,每行包含学生用美元和美分花费的金额。学生人数不超过1000人,学生的学费不超过10,000美元。包含0的单行跟随最后一次旅行的信息。
对于每次旅行,输出一条线,说明必须交换的总金额,以美元和美分来平衡学生的费用。成本。
3
10.00
20.00
30.00
4
15.00
15.01
3.00
3.01
0
$10.00
$11.99
我的代码适用于某些测试用例,但在其他测试用例中失败。我认为这是因为浮动中的精度错误。但是,我无法找到错误。
例如,
输入: 4 9999.1 9999.1 9999.0 9999.1
输出: $ 0.06
但是,输出应该是0.07美元
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#define MAX 1000
using namespace std;
float money[MAX];
int main(){
int numOfStudents;
int i; // loop counter
double average; // of the costs
double negDiff, posDiff; // |amount-average|
double minDiff;
float total; // all the costs added together
while(scanf("%d", &numOfStudents) == 1){
if(numOfStudents == 0){
break;
}
memset(money, 0, sizeof(money));
total = 0;
for(i = 0; i < numOfStudents; i++){ // scan for the cost of each student - input into array
double m;
scanf("%lf", &m);
money[i] = m;
total += m;
}
average = total/numOfStudents;
negDiff = 0;
posDiff = 0;
for(i = 0; i < numOfStudents; i++){ // find the difference between average and each cost -> add together
if(money[i] > average){
posDiff += (long) ((money[i] - average) * 100.0) / 100.0;
}
else{
negDiff += (long) ((average - money[i]) * 100.0) / 100.0;
}
}
minDiff = 0;
if(posDiff > negDiff){ // find the minimum value for all to equal
minDiff = negDiff;
}
else{
minDiff = posDiff;
}
printf("$%.2lf\n", minDiff);
}
return 0;
}
答案 0 :(得分:0)
嗯......你可能是对的。你真的不应该以花车的形式阅读这笔钱。
scanf ("%d.%d", &dollars, &pennies);
int m = dollars * 100 + pennies;
至于解决一般问题,只要确保你坚持整体划分
int average = total / numStudents;
int leftover = total % numStudents;
// numStudents - leftover students need to have paid $average
// leftover students need to have paid $average + 1
int paid = 0;
int recieved = 0;
for (int i = 0; i < numStudents; ++i)
{
// Since we start with the lowest amount owed, money array needs to have been
// sorted such that the student who paid the least comes first.
owed_money = average;
if (i > numStudents - leftover)
owed_money += 1;
if (money[i] < owed_money)
paid += owed_money - money[i];
else if (money[i] > owed_money)
recieved += money[i] - owed_money;
}
assert (paid == recieved);
也许还有更好的方法吗?无论如何,这是一个难题,但我保证你的解决方案不应该包含任何浮点运算。
答案 1 :(得分:0)
如果你将正负差异切成2位小数,也要砍掉平均值。这给出了您期望的结果(简化的工作代码)
#include <stdio.h>
int main() {
int n, i;
double average, negDiff, posDiff, minDiff, total;
while (scanf("%d", &n) == 1 && n != 0) {
double money[n];
total = 0.0;
for (i = 0; i < n; i++) {
scanf("%lf", &money[i]);
total += money[i];
}
average = (long) ((total / n) * 100.0) / 100.0;
negDiff = posDiff = 0.0;
for (i = 0; i < n; i++) {
if (money[i] > average)
posDiff += (long) ((money[i] - average) * 100.0) / 100.0;
else
negDiff += (long) ((average - money[i]) * 100.0) / 100.0;
}
minDiff = posDiff > negDiff ? negDiff : posDiff;
printf("$%.2lf\n", minDiff);
}
return 0;
}
<强>输入强>
3
10.00 20.00 30.00
4
15.00 15.01 3.00 3.01
4
9999.1 9999.1 9999.0 9999.1
0
<强>输出强>
$10.00
$11.99
$0.07
答案 2 :(得分:0)
计算出平均下来仅需减少的零头。这意味着我们将把x美分放入边锅中,由于x将小于n,因此即使您分发它,最终也只会得到很少的收益,而它们将比其他收益多出一美分。因此,它们全都以美分计。
现在这样说。这是简单的代码
int main( )
{
int n;
cin >> n;
while( n ) {
vector<double> v;
while( n-- ) {
double x;
cin >> x;
v.push_back( x );
}
double avg = accumulate( begin(v), end(v), 0.0 ) / v.size();
avg = ((int)(avg*100))/100.00;
double exchange = 0;
for ( auto x : v ) { if ( x < avg ){ exchange += avg - x; } }
cout << exchange << endl;
cin >> n;
}
return 0;
}
并为此输入
3
10.00
20.00
30.00
4
15.00
15.01
3.00
3.01
4
9999.1
9999.1
9999.0
9999.1
0
输出为
10
11.99
0.07