Журнал "Смекайлик"

Ну и кто победил в сравнении?

Задача If12, например, решается так:

  writeln(ReadSeqReal(3).Min());

Задача If13:

  write(ReadSeqReal(3).Sorted.ElementAt(1));

var str := String.Empty;

я бы писал

var str := '';

Примеры с последовательностями интересны, но далеко выходят за рамки темы заданий. В них ведь отрабатываются только навыки использования условного оператора if.

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

Традиционно в Си-шарпе пустая строка определяется так

var str = String.Empty;

В паскале, вероятно, так var str := ‘’;

Но это разница непринципиальная.

Кто победил? - Если брать только школьные примеры, то победила дружба. Практически безразлично, на каком языке решать школьные примеры - на Питоне или на паскале. С точки зрения изучения программирования, гораздо важнее придумать/разработать эффективный алгоритм решения задачи, чем переписать его на паскаль или Питон, поскольку это дело техники.

Если говорить о развитии алгоритмического мышления, то для реализации алгоритмов нужно выбирать более простой язык программирования, иначе всё учебное время уйдёт на изучение самого языка, а не на решение задач.

И Питон, и паскаль на школьном уровне можно выучить максимум за месяц. Всё остальное время нужно использовать их для решения задач.

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

Сравнение языков можно продолжить. Есть ещё немало интересных задач для этого…

В десятом номере журнала “Смекайлик” 6 графических проектов на Си-шарпе, которые нетрудно переписать на паскаль.

В одиннадцатом номере журнала “Смекайлик” 11 графических проектов на Си-шарпе, которые можно переписать на паскаль.

Предлагаю всем желающим решить на паскале задачу 2.05 из книги Савина «Занимательные математические задачи».

Она адресована школьникам, так что её вполне разумно решать на компьютере – иначе зачем вообще изучать программирование?


Впишите в квадратики цифры 1, 2, …, 9, каждую по одному разу так, чтобы произведение оказалось наибольшим.


Это реальная задача, а не учебная из Электронного задачника Абрамяна. На таких задачах сравнение Питона и паскаля более объективно.

Вариант решения на Питоне будет представлен через неделю.

Можно без программирования предположение сделать? 963852741 по идее должно быть наибольшим, если я правильно условие понял. Или задача реализовать вписывание чисел в квадратики?)

Ответ и без предположений можно найти в книге:smile: 941 * 852 * 763

Так что Ваше предположение почти верное, но речь, конечно, не о том, чтобы угадать ответ, а о том, чтобы найти его программным путём.

Вписывать числа в квадратики не нужно - ни программным путём, ни естественным, ни противоестестественным…

В двенадцатом номере журнала "Смекайлик" новые графические проекты на Си-шарпе. Попробуйте переписать на паскаль!

Время вышло, ответа нет - вот результат изучения программирования в школе: нулевой:weary:

А на Питоне задача решается просто:smiley:

from itertools import permutations

# макс. произведение:
max = 0

# перестановки 9 цифр:
for p in permutations(range(1, 9+1)):
    # первое трёхзначное число:
    n1 = p[0] * 100 + p[1] * 10 + p[2]
    # второе трёхзначное число:    
    n2 = p[3] * 100 + p[4] * 10 + p[5]
    # третье трёхзначное число:
    n3 = p[6] * 100 + p[7] * 10 + p[8]
    # их произведение:
    m = n1 * n2 * n3
    # больше максимального?
    if (m >= max):
        max = m
        mults = str(n1) + " * " + str(n2) + " * " + str(n3)
        print(max, mults);


# печатаем ответ
print("Наибольшее произведение =", max)
input()

а сколько по времени отрабатывает ваш алгоритм? Вот, например, такое себе алгоритмическое решениеЖ

var
  a, b, c, Ma, Mb, Mc, M: integer;
  p, d: array[0..9] of integer;
  finded: boolean;
  prod: integer;

begin
  Milliseconds();
  
  M := 0;
  for var j := 0 to 9 do
    p[j] := Round(Power(10, j));
  
  for var i := 123456789 to 987654321 do
  begin
    
    finded := false;
    var j := 1;
    while (j <= 9) and not finded do
    begin
      d[j] := (i mod p[j]) div p[j - 1];
      if d[j] = 0 then finded := true;
      var k := j - 1;
      while (k >= 1) and not finded do
      begin
        if d[j] = d[k] then
          finded := true
        else
          k := k - 1;
      end;
      j := j + 1;
    end;
    if not finded then
    begin
      a := i div 1000000;
      b := i div 1000 - a * 1000;
      c := i mod 1000;
          //writeln('-', a,b,c);
      prod := a * b * c;
      if prod > M then
      begin
        M := prod;
        Ma := a;
        Mb := b;
        Mc := c;
      end;
    end;
  end;
  var time := MillisecondsDelta();
  writeln('Миллисекунд: ', time);  
  writeln('---:', Ma, Mb, Mc);
end.
  • Миллисекунд: 126254
  • —:763852941

а это попытка получить все перестановки… При установке range(1,8) уже не хватает стека. Как это можно обойти?

 program permutation;
    
    type
      seqOfInt = sequence of integer;
    
    function GetPermutations(var s: seqOfInt): sequence of seqOfInt;
    var
      NextStep: seqOfInt;
      c, cc: integer;
      Perms: sequence of seqOfInt;
    begin
      
      if s.Count = 2 then
        Perms := Seq(s, s.Take(1) + s.Skip(1))
      else 
      begin
        c := 0;
        foreach var e in s do
        begin
          NextStep := s.Take(c) + s.Skip(c + 1);
          
          cc := 0;
          foreach var perm in GetPermutations(NextStep) do
          begin
            if (cc = 0) and (c = 0) then 
            begin
              Perms := Seq(e + perm);
              cc := 1;
            end
            else
              Perms := Perms + Seq(e + perm);
          end;
          
          c += 1;
        end;
      end;
      
      Result := Perms;
    end;
    
    begin
      var s: seqOfInt;
      s := Range(1, 7);
      
      writeln(s);
      writeln('---------------');
      
      var AllPerms: sequence of seqOfInt;
      
      Milliseconds();
      AllPerms := GetPermutations(s);
      var time := MillisecondsDelta();
      writeln('Миллисекунд: ', time);
      
      {foreach var perm in AllPerms do
        writeln(perm);}
      
      writeln('Количество: ', AllPerms.Count);
    end.

Без печати промежуточных результатов около 520 миллисекунд. Такое “алгоритмическое” решение никуда не годится.

Подход верный, но нужно искать более эффективный алгоритм генерации перестановок. Примеры таких алгоритмов найти несложно.

Вот нет в Си-шарпе встроенных комбинаторных методов - и в паскале нет. А многие задачи решаются комбинаторно.

Кстати, программка на C++ укладывается примерно в 2 миллисекунды, хотя довольно чувствительна к аккуратности написания кода.

Эту программку ведь тоже нужно написать. По сравнению с Питоном на это остаётся ещё полсекунды.

Решение задачи на паскале с привлечением библиотеки на Си-шарпе:smile:

_Projects.rar (56,9 КБ)

Скорость - в 10 раз меньше, чем на Питоне. Вероятно, библиотека не очень быстрая…:cold_sweat:

Мне бы хватило – я просто вашу программу в C++ засунул, с небольшими доработками:

#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>

using namespace std;

int main(int argc, char* argv[])
{
	//  max произведение
	int max(0);
	//  рабочий вектор и вектор результатов
	vector<char> p = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, result;
		
	// перестановки 9 цифр:
	while (next_permutation(p.begin(), p.end())) {
		//  первое трёхзначное число :
		int n1 = p[0] * 100 + p[1] * 10 + p[2];
		// второе трёхзначное число :
		int n2 = p[3] * 100 + p[4] * 10 + p[5];
		// третье трёхзначное число :
		int n3 = p[6] * 100 + p[7] * 10 + p[8];
		// их произведение :
		int m = n1 * n2 * n3;
		// больше максимального ?
		if (m >= max) {
			max = m;
			result = p;
		}
	}
	

    //  печатаем ответ
    	cout << "Max product = " << max << endl;
    	copy(result.begin(), result.end(), ostream_iterator<int>(cout, " "));
    
    	system("pause");
    	return 0;
    }

Мне кажется, это не тот пример, который для обучения подходит. Безусловно, Питон тут выглядит получше Паскаля, но такие алгоритмы можно на Питоне писать только после того, как Вы объясните работу алгоритма permutations, и расскажете, как устроен и работает range. Но это так, на правах личного мнения. Я понимаю, что Питон удобен, лаконичен и красив, но числодробительные алгоритмы – явно не его конёк.

Решить задачу - значит придумать алгоритм её решения. Понятно, что его можно записать на любом языке программирования, а на языке C++ он будет работать быстрее всего.

В данном случае решение и на Питоне, и на C++ одно и то же, поскольку реализует один и тот же алгоритм. Это не новое решение. Но на Питоне исходный код выглядит гораздо проще и понятнее. Это важно, когда мы имеем в виду обучение программированию.

Что касается задачи, то она безусловно учебная, так как публиковалась в журнале “Квант” для школьников. Естественно, предполагалось, что её будут решать не на компьютере, а на бумаге. Но как её можно решить иначе, чем перебором? А переборные задачи - это задачи для компьютера, а не для людей. На мой взгляд, именно эта задача хорошо показывает, для чего нужен компьютер.

Перестановки изучают в детском саду и в младших классах средней школы. Как и некоторые другие комбинаторные объекты. Правда, при этом обходятся без “научных” терминов, но это сути дела не меняет. Функция range выдаёт арифметическую последовательность, которая известна ученикам пятого класса. Работу алгоритма permutations объяснять не обязательно. Как известно, придумано много алгоритмов для генерирования перестановок. Какой именно реализован в Питоне я не знаю, хотя и догадываюсь. Мешает ли мне это “незнание” решить задачу? - Ничуть!

В бесполезной книге “Полезное программирование. Уникальное руководство к действию” вы можете прочитать, как автор отбирает кандидатов на работу, предлагая им написать программу для пузырьковой сортировки. Точно такой же ерундой занимаются и в школе. Вместо программирования изучают во всех подробностях тонкости и хитрости языка паскаль. Нам нужен паскаль или умение решать задачи? Не надо копать яму детским совком! Уже давно изобрели экскаваторы - большие для больших ям, маленькие - для маленьких. И в Питоне, и в паскале имеются встроенные функции и методы для сортировки последовательностей. Но можно пару часов изучать никому ненужную пузырьковую сортировку.

Хотелось бы видеть на форуме больше реальных проектов, а пока он больше напоминает книгу жалоб и предложений.

1 лайк

Отлично. Полностью согласен.

А скажите - вот, мы после этого, разумеется, напишем в PascalABC.NET стандартную функцию NextPermutation. Изменится ли после этого ваше сравнение Питона и Паскаля?

Ув. Валерий, мне кажется, что решить задачу – это всё-таки сначала подобрать подходящие инструменты, а потом с учётом этих инструментов написать алгоритм и реализовать его для выбранного инстументария.

Приведённый пример смущает меня тем, что выбранный Вами для решения задачи инструмент работает в сотни раз медленней, чем это могло бы быть. В действительности это не важно, мы же алгоритмы изучаем, а не языки, но «осадочек» остался – в таких задачах Питон как раз и выступает в роли детского совочка.

Хотите показать красоту и удобство Питона? Напишите какие-нибудь действительно интересные проекты – например, собрать в архив все файлы с текстами программ из какой-нибудь папки, засунуть в архив и отправить на указанный электронный адрес. Чем не реальный проект? Уверен, тут Питон всех победит.

1 лайк