Как лучше всего решить проблему «Студенты и шкафчики»?

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

В идеале решения должны быть представлены в псевдокоде с большой классификацией О. Доказательство этой классификации - подливка. К проблеме:

Есть N закрытых шкафчиков и N студентов. Первый ученик открывает каждый шкафчик. Второй ученик открывает или закрывает каждый второй шкафчик. Это продолжается, когда n-й ученик открывает и закрывает каждый n-й шкафчик. Какие шкафчики открываются после N учеников? Сколько шкафчиков открыто?

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

Erick 07.11.2008 20:44

Я хотел бы знать, считает ли кто-нибудь вопрос: stackoverflow.com/questions/1269202/… дублированием этого.

Brad Gilbert 13.08.2009 05:17
За пределами сигналов Angular: Сигналы и пользовательские стратегии рендеринга
За пределами сигналов Angular: Сигналы и пользовательские стратегии рендеринга
TL;DR: Angular Signals может облегчить отслеживание всех выражений в представлении (Component или EmbeddedView) и планирование пользовательских...
Sniper-CSS, избегайте неиспользуемых стилей
Sniper-CSS, избегайте неиспользуемых стилей
Это краткое руководство, в котором я хочу поделиться тем, как я перешел от 212 кБ CSS к 32,1 кБ (сокращение кода на 84,91%), по-прежнему используя...
4
2
5 444
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Ответ принят как подходящий

Учащиеся меняют только состояние тех шкафчиков, на которое их число делится (ученик 2 переворачивает четные шкафчики, ученик 3 переворачивает шкафчики, кратные 3, и так далее и так далее ...). Итак, единственные шкафчики, которые останутся открытыми после N раундов, - это те, у которых нечетное количество делителей (поскольку они начинаются закрытыми, нечетное количество флипов оставит их открытыми). Единственные числа с нечетным числом делителей - это точные квадраты, поэтому все шкафчики с точными номерами останутся открытыми. Таким образом, после N раундов количество открытых шкафчиков будет равно квадратному корню (полному) из N.

Это решение будет O (sqrt (N)), чтобы знать, что шкафчики именно то, что открыты, но O (1), если вам нужно только знать, что шкафчики сколько открыты.

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

Bill the Lizard 09.11.2008 05:38

В O (log N) на основе интервала открытых шкафчиков, следующих за серией 1 + 2k:

delta=1

for(index=1;index < N;index+=delta) {
   print open locker = index;
   delta+=2;
   opencount++;
};

Это не может быть O (log N), потому что открытых шкафчиков √N, и вам нужно распечатать их все. Кроме того, сумма первых k нечетных чисел равна k ^ 2, поэтому ваш код - это просто сложный способ распечатать все квадратные числа меньше N. :-)

ShreevatsaR 08.11.2008 06:56

Я думал, что посмотрю, как быстро я смогу найти решение на Perl.

use strict;
use warnings;
use 5.010;

sub lockers{
  my($number_of_lockers) = @_;

  my $largest_sqrt = sqrt $number_of_lockers;

  my @list;

  for( my $index = 1; $index <= $largest_sqrt; ++$index ){
    push @list, $index**2;
  }

  return @list;
}

say for lockers 100;
1
4
9
16
25
36
49
64
81
100

Или, если вы не хотите вычислять квадратный корень из количества шкафчиков.

use strict;
use warnings;
use 5.010;

sub lockers{
  my($number_of_lockers) = @_;

  my @list;

  for(
    my($index,$sqr) = (1,1);
    $sqr <= $number_of_lockers;
    $sqr = (++$index)**2
  ){
    push @list, $sqr;
  }

  return @list;
}

say for lockers 100;

Просто получил это как домашнее задание.

for(int i = 0; i < SIZE / 2; i++){
   for(int k = i; k < SIZE; k = k+i+1){
      if (lockers[k] == false)
        lockers[k] = true;
      else
        lockers[k] = false;
   }
}

Вы можете оптимизировать это, удалив операторы if и заменив их одним lockers[k] = !lockers[k], поскольку это просто инвертирование

Opal 17.06.2012 05:07

Ниже приведен java-код с использованием метода грубой силы. Он проверяет каждого ученика и то, что он делает с каждым конкретным шкафчиком. Есть подход получше. Предположим, что есть 100 учеников и 100 шкафчиков. Затем к шестому шкафчику прикоснутся Студент 1, Студент 2 и Студент 3. 1X1, 2X3, 3X2. Но только шкафчики с квадратами будут иметь четное количество учеников, которые их касаются.

Таким образом, лучше всего найти квадраты между числами.

Код Java:

  int l, s;
  Scanner in = new Scanner(System.in);
  System.out.println("Enter the number of lockers");
  l = in .nextInt();
  System.out.println("Enter the number of students");
  s = in .nextInt();
  if (l

   boolean lockers[] = new boolean[l + 1]; 
   boolean students[] = new boolean[s + 1]; lockers[0] = true; students[0] = true;
   for (int i = 1; i <= l; i++) {
lockers[i] = false;
   }

   for (int j = 1; j <= s; j++) {
for (int h = 1; h <= l; h++) {
 if (h % j == 0) {
  if (lockers[h] == true) lockers[h] = false;
  else lockers[h] = true;
 }

}
 }
   System.out.println("the lockers which are open are ");
   for (int k = 1; k <= l; k++) {
       if (lockers[k] == true) {
       System.out.print(" " + k);
   }
 }

Это просто неформатированный код без каких-либо объяснений того, как он работает.

425nesp 21.07.2015 10:35

Простое решение с минимумом кода.

Автор: Моаззам Али

   public class CH3 {

`public static void main (String [] args) { логическое [] lockers = новое логическое [100];

    for(int i=0;i<100;i++){
        lockers[i]=true;
                          }

    for(int s=2;s<100;s++){
        for(int y=s; y<100;y=y+s){
            if (lockers[y]==true){
                lockers[y]=false;
                               }
            else{
                lockers[y]=true;
                }
                              }
                          }
System.out.println("open lockers are:");
for(int i=0;i<100;i++){
if (lockers[i]==true){


System.out.print(i+"  ");
}
}   

}}

Вот мой ответ без использования массивов (или объектов и т. д.) И без использования метода квадратного корня.

====

включают

используя пространство имен std;

int main () {

int studentTotal, lockerTotal, visit, totalOpened = 0, totalClosed = 0;

cout << "Введите количество студентов" << endl; cin >> studentTotal;

lockerTotal = studentTotal;

for (int locker = 1; locker <= lockerTotal;  locker++ ){ // locker loop
    cout << "\n\n\nLocker no." << locker << endl;
    cout << " is visited by student(s) ";
    visit = 0;
    for (int student = 1 ; student <= studentTotal; student++) { // student loop

    if ( locker % student == 0) {
            cout << student << ", ";
            visit++;}

    }//end of locker loop

    cout << "\nTotal number of visits: " << visit;
    if (visit % 2 == 0){
        cout << " the locker will stay closed.";
        totalClosed++;}
    else { cout << " the locker will be opened.";
        totalOpened++;}

} //end of student loop

if (lockerTotal == totalOpened + totalClosed) {
    cout << "\n\n\nOf total lockers (" << lockerTotal << "), " << totalOpened << " will be left open." << "(" << totalClosed << ") " << "will be closed." << endl;
    }else cout << "Error!!";



return 0;

}

Другие вопросы по теме