我认为提出一些经典的CS问题并让人们展示他们的算法优化技巧会很有趣。希望我们能够看到一些巧妙的技术来解决我们可能在实践中实现的抽象问题。
理想情况下,解决方案将以具有大O分类的伪代码呈现。该分类的证明是肉汁。关于问题:
有N个封闭的储物柜和N个学生在场。第一个学生打开每个储物柜。第二个学生打开或关闭每个第二个储物柜。这继续在第n名学生打开和关闭每个第n个储物柜的地方。 N学生之后什么储物柜开着?有多少个储物柜是开着的?
答案 0 :(得分:19)
学生只会翻转这些储物柜的状态,他们的号码是其除数(学生2翻转偶数储物柜,学生3翻转可被3整除的储物柜,依此类推......)。因此,在N轮之后将保持打开的唯一储物柜是那些具有奇数除数的储物柜(因为它们开始关闭,奇数翻转将使其打开)。唯一具有奇数除数的数字是完美的正方形,因此所有完美正方形编号的储物柜都将保持打开状态。因此,在N轮之后,保持打开的储物柜的数量将是N的平方根(平铺)。
这个解决方案是O(sqrt(N))知道确切地打开哪个储物柜,但是如果您只需要知道多少储物柜,则为O(1)是开放的。
答案 1 :(得分:2)
这是我的答案,不使用数组(或对象等)而不使用平方根方法。
====
使用namespace 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;
}
答案 2 :(得分:0)
在O(log N)中,基于系列1 + 2k之后的开放式储物柜的间隔:
delta=1
for(index=1;index < N;index+=delta) {
print open locker = index;
delta+=2;
opencount++;
};
答案 3 :(得分:0)
我想我会看到我能用多快的速度在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;
答案 4 :(得分:0)
刚刚将此作为一项新任务。
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;
}
}
答案 5 :(得分:0)
代码最少的简单解决方案。
作者:Moazzam Ali
public class CH3 {
`public static void main(String [] args){ boolean [] lockers = new boolean [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+" ");
}
}
}}
答案 6 :(得分:-1)
以下是使用强力方法的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);
}
}