"旅行"编程挑战

时间:2015-07-01 04:18:07

标签: c++ floating-point

这就是问题所在。

  

一群学生是每年到不同地点旅行的俱乐部的成员。他们过去的目的地包括印第安纳波利斯,凤凰城,纳什维尔,费城,圣何塞和亚特兰大。今年春天,他们计划去埃因霍温旅行。

     

该小组事先同意平均分摊费用,但分摊每项费用并不实际。因此,团体中的个人支付特定的费用,例如餐饮,酒店,出租车和机票。旅行结束后,每个学生的费用都计算在内,并且交换金钱,以便每个学生的净费用相同,在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;
}

3 个答案:

答案 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

请参阅http://ideone.com/cxhvlL

答案 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