#java #алгоритм
наша задача - для заданного числа человек N и заданного шага K - определить номер счастливчика который останется последним в этой жеребьёвке. Например если всего 10 человек и выбывает каждый 3-й: N = 10, K = 3 последовательность "вылета" будет такой (в скобках указаны выбывающие номера): 1-й круг: 1 2 (3) 4 5 (6) 7 8 (9) 10 2-й круг: 1 (2) 4 5 (7) 8 10 3-й круг: (1) 4 5 (8) 10 4-й круг: 4 (5) 10 5-й круг: 4 (10) итак победителем оказался тот кто стоял четвертым в начальной позиции. Входные данные содержат количество человек N и размер шага K. Ответ должен содержать "выигрышный номер" (считая с 1). Имеется вопрос насчёт того, как после окончания первого круга во втором круге начать удаление не со второго элемента, а с первого уже package com.company; import java.util.ArrayList; public class Main { public static void main(String[] args) { ArrayListlist1 = new ArrayList(); int n = 88; int sh = 6; for (int i = 0; i Ответы
Ответ 1
Это двухтысячелетняя задача Иосифа Флавия в современной формулировке: идём ко кругу, убиваем каждого K-ого, последний выживает. Вопрос на какую позицию в круге от начала отсчёта встать, чтобы выжить, если всего N людей. Линейное решение — O(n) Есть простой линейный (O(n))алгоритм на основе рекуррентного соотношения: g(1, k) = 0 g(n, k) = (g(n-1, k) + k) % n где g(n, k) это индекс безопасного места в массиве (0 <= g(n, k) < n). Для примера в вопросе (отсчёт от единицы): public class Josephus { public static void main(String[] argv) { System.out.println(safe_position(10, 3)); } public static int safe_position(int n, int k) { int g = 0; for (int i = 0; i < n; ++i) g = (g + k) % (i + 1); return g + 1; } } Реализация транслирована на Java из решения на Питоне. O(k log n) Для маленьких k и больших n можно использовать O(k log n) решение: public class JosephusLog { public static void main(String[] argv) { System.out.println(safe_position_log(2147483647, 3)); } public static int safe_position_log(int n, int k) { double x = k * (double) n; while(x > n) { x = (long)((k * (x - n) - 1) / (k - 1)); } return (int)x; } } Замкнутая формула — O(1) Могут существовать и замкнутые формулы (O(1) решение для n,k размером с машинное слово). К примеру, для k=2 (достаточно старший бит в конец записать). Вот реализация на Java O(1) решения для k=3 (за постоянное время, не зависящее от n), из статьи The Josephus Problem by Lorenz Halbeisen: public class Josephus3 { public static void main(String[] argv) { System.out.println(safe_position3(10)); } public static int safe_position3(int n) { // j(n, k, n-l) = (n - c_m) * k + d_m; // return j(n, 3, n) + 1; switch(n) { case 1: case 4: return 1; case 2: case 3: return 2; default: assert(n >= 5); int k = 3; double alpha = 0.8111352513650005; // theorem 2 [jos] k = 3; l = 0; double q = k / (double)(k-1); long m = Math.round(Math.log(n / alpha) / Math.log(q)); // n >= 5 double e_m = alpha * Math.pow(q, m); long c_m = Math.round(e_m); if (c_m > n) { m -= 1; e_m /= q; c_m = Math.round(e_m); } assert(c_m <= n); // c_m <= n < c_m_plus_1 int d_m = (e_m - c_m) < 0 ? 1 : 0; return (int)((n - c_m) * k + d_m + 1); } } } Решение работает для всех int n от 1 до 2147483647.Ответ 2
package com.company; import java.util.ArrayList; public class MyClass { public static void main(String[] args) { ArrayListlist1 = new ArrayList(); int n = 10; int k = 3; for (int i = 0; i
Комментариев нет:
Отправить комментарий