Наименьшее количество избирателей, учитывая две половины - PullRequest
6 голосов
/ 23 октября 2010

Один из моих бывших учеников прислал мне сообщение об этом вопросе интервью, который он получил во время подачи заявки на работу младшим разработчиком.

На поддельных выборах в классе баллотируются два кандидата в президенты. Учитывая два процента избирателей, выясните наименьшее количество возможных избирателей в классе.

Примеры:

Ввод: 50,00,50,00
Выход: 2

Ввод: 25,00,75,00
Выход: 4

Ввод: 53,23, 46,77
Выход: 124 // Первое значение, 1138, было неверным. Спасибо Loïc за правильное значение

Примечание: сумма входных процентов всегда равна 100,00%, два десятичных знака

Последний пример заставил меня почесать голову. Это был первый раз, когда я услышал об этой проблеме, и я как бы озадачен, как решить эту проблему.

РЕДАКТИРОВАТЬ: Я позвонил своему ученику по поводу проблемы, и сказал мне, что он не был уверен в последнем значении. Он сказал, и я цитирую: «Это был абсурдно большой вывод» :( извините! Я должен был исследовать больше, прежде чем публиковать его в Интернете ~ Я предполагаю, что 9,797 - это вывод в последнем примере, хотя ..

Ответы [ 5 ]

8 голосов
/ 23 октября 2010

Вы можете вычислить эти значения, используя наилучшие рациональные приближения процентов избирателей.Википедия описывает, как получить эти значения из непрерывной дроби (которую можно вычислить, используя евклидов алгоритм ).Желаемым результатом является первое приближение, которое находится в пределах 0,005% от ожидаемого значения.

Вот пример с 53,23%:

10000 = 1 * 5323 + 4677
5323  = 1 * 4677 + 646
4677  = 7 * 646  + 155
646   = 4 * 155  + 26
155   = 5 * 26   + 25
26    = 1 * 25   + 1
25    = 25* 1    + 0

Approximations:
1:   1 / 1
 -> 1 = 100%
2:   1 / (1 + 1/1) 
 -> 1/2 = 50%
2.5: 1 / (1 + 1 / (1 + 1/6))
 -> 7/1 = 53.75%
3:   1 / (1 + 1 / (1 + 1/7))
 -> 8/15 = 53.33%
3.5: 1 / (1 + 1 / (1 + 1 / (7 + 1/3)))
 -> 25/47 = 53.19%
4:   1 / (1 + 1 / (1 + 1 / (7 + 1/4)))
 -> 33/62 = 53.23%

Причина, по которой у нас есть дополнительные значения до 3-го и 4-госходится то, что их последние члены (7 и 4 соответственно) больше 1, поэтому мы должны проверить аппроксимацию с уменьшением последнего члена.

Желаемый результат - знаменатель первого значения, которое округляется до желаемогозначение, которое в этой вазе равно 62.

Пример реализации Ruby доступен здесь (при использовании формул со страницы Википедии здесь , поэтому он выглядит немного иначе, чем вышепример).

4 голосов
/ 23 октября 2010

Сначала вы можете заметить, что тривиальное решение состоит в том, чтобы набрать 10.000 избирателей.Теперь давайте попробуем найти что-то меньшее, чем это.

For each value of N starting à 1
  For Each value of i starting à 1
     If i/N = 46.77
       return N

Всегда выбирайте минимум двух процентов, чтобы быть быстрее.

Или быстрее:

For each value of N starting à 1
  i = floor(N*46.77/100)
  For j = i or i+1 
     If round(j/N) = 46.77 and round((N-j)/N) = 53.23
       return N


Для третьего примера:
  • 605/1138 = .5316344464
  • (1138-605) / 1138 = .4683655536

, но

  • 606/1138 = .5325131810
  • (1138-606) / 1138 = .4674868190

Это не может быть 1138 ...

Но 62 работает:

  • 33/62 = .5322580645
  • (62-33) / 62 = .4677419355

Округлено этодавая вам хорошие значения.

2 голосов
/ 23 октября 2010

(после некоторых обширных правок:)

Если у вас есть только 2 избирателя, вы можете сгенерировать только следующие проценты для кандидатов А и В:

0+100, 100+0, or 50+50

Если у вас есть 3 избирателя, то у вас есть

0+100, 100+0, 33.33+66.67, 66.67+33.33 [notice the rounding]

Так что это забавная задача о дробях.

Если вы можете сделать 25%, то вам нужно иметь как минимум 4 человека (так что вы можете сделать 1/4, так как 1/2 и 1/3 не будут сокращать его). Вы можете сделать это больше (то есть 2/8 = 25%), но проблема требует наименьшего.

Однако для более интересных дробей требуются числа больше 1 в числителе:

2/5 = 40%

Так как вы не можете получить это ни с чем, кроме 2 или более в числителе (1 / x никогда не обрежет это).

Вы можете сравнивать на каждом шаге и увеличивать числитель или знаменатель, что намного эффективнее, чем итерация по всему пространству выборки для j, а затем увеличение i;

т.е. если у вас есть процент в 3%, проверка решений до 96/99, 97/99, 98/99, прежде чем даже перейти к х / 100, - пустая трата времени. Вместо этого вы можете увеличить числитель или знаменатель в зависимости от того, насколько хорошо работает ваше текущее предположение (больше или меньше), например

int max = 5000; //we only need to go half-way at most.

public int minVoters (double onePercentage) {

    double checkPercentage = onePercentage;
    if (onePercentage > 50.0)
        checkPercentage = 100-onePercentage; //get the smaller percentage value

    double i=1;
    double j=1; //arguments of Math.round must be double or float
    double temp = 0;

    while (j<max || i<max-1) { //we can go all the way to 4999/5000 for the lesser value

        temp = (i/j)*100;
        temp = Math.round(temp);
        temp = temp/100;

        if (temp == checkPercentage)
            return j;

        else if (temp > checkPercentage) //we passed up our value and need to increase the denominator
            j++;

        else if (temp < checkPercentage) //we are too low and increase the numerator
            i++;
    }

    return 0; //no such solution
}

Пошаговый пример поиска знаменателя, который может дать 55%

   55/100 = 11/20 

   100-55 = 45 = 9/20 (checkPercentage will be 45.0)


1/1 100.0%  
1/2 50.00%  
1/3 33.33%  
2/3 66.67%  
2/4 50.00%  
2/5 40.00%  
3/5 60.00%  
3/6 50.00%  
3/7 42.86%  (too low, increase numerator)  
4/7 57.14%  (too high, increase denominator)  
4/8 50.00%  
4/9 44.44%  
5/9 55.56%  
5/10 50.00%  
5/11 45.45%  
6/11 54.54%  
6/12 50.00%  
6/13 46.15%  
6/14 42.86%  
7/14 50.00%  
7/15 46.67%  
7/16 43.75%  
8/16 50.00%  
8/17 47.06%  
8/19 42.11%  
9/19 47.37%  
9/20 45.00% <-bingo

Приятной особенностью этого метода является то, что он будет выполнять только (i + j) шагов, где i - числитель, а j - знаменатель.

0 голосов
/ 25 октября 2010

Тогда ответ, который прыгнул в мою голову, был скорее грубым подходом.Может быть не более 5001 уникального ответа, потому что между 00.00 и 50.00 существует 5001 уникальное число.Следовательно, почему бы не создать и сохранить справочную таблицу.Очевидно, что не будет 5001 уникального ответа, потому что некоторые ответы будут повторяться.Суть в том, что есть только 5001 правильных дробей, потому что мы округляем до двух цифр.

int[] minPossible = new int[5001];
int numSolutionsFound = 0;
N = 2;
while(numSolutionsFound < 5001) {
  for(int i = 0 ; i <= N/2 ; i++) {
    //compute i/N 
    //see if the corresponding table entry is set 
    //if not write N there and increment numSolutionsFound   
  }
  N++;
}

//Save answer here

Теперь решение - это просто таблица поиска."правильный".Но я НИКОГДА не придумаю это промежуточное интервью.Тем не менее, я бы знал, что подобное возможно, но я не смогу выманить это на месте.

0 голосов
/ 23 октября 2010

Я не вижу актуальности этого вопроса для должности младшего разработчика.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...