Я подумал, что было бы интересно представить классические задачи CS и позволить людям показать свои навыки оптимизации алгоритмов. Надеюсь, что мы увидим некоторые умные методы решения абстрактных проблем, которые мы сможем реализовать на практике.
В идеале решения должны быть представлены в псевдокоде с большой классификацией О. Доказательство этой классификации - подливка. К проблеме:
Есть N закрытых шкафчиков и N студентов. Первый ученик открывает каждый шкафчик. Второй ученик открывает или закрывает каждый второй шкафчик. Это продолжается, когда n-й ученик открывает и закрывает каждый n-й шкафчик. Какие шкафчики открываются после N учеников? Сколько шкафчиков открыто?
Я хотел бы знать, считает ли кто-нибудь вопрос: stackoverflow.com/questions/1269202/… дублированием этого.


Учащиеся меняют только состояние тех шкафчиков, на которое их число делится (ученик 2 переворачивает четные шкафчики, ученик 3 переворачивает шкафчики, кратные 3, и так далее и так далее ...). Итак, единственные шкафчики, которые останутся открытыми после N раундов, - это те, у которых нечетное количество делителей (поскольку они начинаются закрытыми, нечетное количество флипов оставит их открытыми). Единственные числа с нечетным числом делителей - это точные квадраты, поэтому все шкафчики с точными номерами останутся открытыми. Таким образом, после N раундов количество открытых шкафчиков будет равно квадратному корню (полному) из N.
Это решение будет O (sqrt (N)), чтобы знать, что шкафчики именно то, что открыты, но O (1), если вам нужно только знать, что шкафчики сколько открыты.
Многие временные алгоритмы, включающие последовательности с повторяющимися шаблонами, можно сжать до простой формулы. Это был хороший пример, для этого нужно немного знать теорию чисел. Мне нравится это.
В 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. :-)
Я думал, что посмотрю, как быстро я смогу найти решение на 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], поскольку это просто инвертирование
Ниже приведен 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);
}
}
Это просто неформатированный код без каких-либо объяснений того, как он работает.
Простое решение с минимумом кода.
Автор: Моаззам Али
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;
}
Нет, это просто развлечение. Я уверен, что это много раз давали в качестве домашнего задания.