БлогNot. 10 не пригодившихся задач за октябрь 2021

10 не пригодившихся задач за октябрь 2021

Небольшой отрицательный рост количества задач в этой заметке по сравнению даже с предыдущей порцией обусловлен, конечно, происками врагов - приезжают к нам, ставят вакцины воруют задачи, а потом в Гейропе справки покупают, что привиты Кембриджем!

Тем не менее, чтобы фарш не протухал и его покупали (в моём "супермаркете" путинский килограмм "домашнего" фарша, то есть, 700 грамм, в этом году стабильно превратился в 400 грамм при сохранении цены), скину лог сейчас, к календарному окончанию месяца.

Все программы выполнялись в консоли актуальной сборки Visual Studio 2019, для поиска на странице нужных слов нажимайте комбинацию клавиш Ctrl+F в браузере.

Темами для мини-исследований могут послужить задачи 3-4, 6, 7.

1. Представить строку std::string в однобайтовой кодировке ASCII как совокупность двоичных значений (байт).

#include <iostream>
#include <string>
using namespace std;

int main() {
 string src = "ABCАБВ", dest;
 for (size_t i = 0; i < src.size(); i++) {
  for (unsigned char j = 0x80; j; j >>= 1) 
   dest += j & src[i] ? '1' : '0';
  dest += " ";
 }
 cout << dest;
 return 0;
}

2. Вывести расстояние от точки x до ближайшей границы интервала [k;l]. Если точка не принадлежит интервалу, расстояние выводится как отрицательное значение.

#include <iostream>
#include <algorithm>
using namespace std;

int main() {
 double k = -2, l = 5, x = 2;
 cout << min(x - k, l - x);
 return 0;
}

3. Найти угол в градусах между часовой и минутной стрелками на 12-часовом циферблате.

#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;

int main() {
 double hh = 6, mm = 16.36; //Исходное время в часах и минутах
 double hour_angle = 0.5 * (hh * 60 + mm);
 double minute_angle = 6 * mm;
 double angle = abs (hour_angle - minute_angle);
 angle = min (360 - angle, angle);
 cout << angle;
 return 0;
}

Если округлять минуты до целых, вот примерное время, когда угол между стрелками будет 90 градусов. Всего 44 раза в сутки.

struct hm { size_t h,m; };
hm tm[] = {
  {00,16},  {00,49},  {01,22},  {01,55},  {02,27},  {03,00},  {03,33},  {04,05},  {04,38},  {05,11},
  {05,44},  {06,16},  {06,49},  {07,22},  {07,55},  {08,27},  {09,00},  {09,33},  {10,05},  {10,38},
  {11,11},  {11,44},  {12,16},  {12,49},  {13,22},  {13,55},  {14,27},  {15,00},  {15,33},  {16,05},
  {16,38},  {17,11},  {17,44},  {18,16},  {18,49},  {19,22},  {19,55},  {20,27},  {21,00},  {21,33},
  {22,05},  {22,38},  {23,11},  {23,44}
};

4. По заданному натуральному углу между часовой и минутной стрелками (от 0 до 180 градусов) найти все комбинации значений часов и минут, когда угол между стрелками составляет заданную натуральную величину u (от 0 до 180 градусов).

Так как решение задачи сводится к невозможному в общем виде решению диофантова уравнения вида 2*u = 60*h - 11*m, где u - заданный угол между стрелками в градусах, h и m - неизвестные часы и минуты, кроме того, заданный угол почти всегда достигается не в целое значение минут (см. предыдущую задачу), остановимся пока на таком вот переборном решении с "допуском" в 3 минуты.

#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;

size_t calcAngle(size_t hh, size_t mm) {
 double hour_angle = 0.5 * (hh * 60. + mm);
 double minute_angle = 6. * mm;
 double angle = abs(hour_angle - minute_angle);
 return abs((long)angle) % 180;
}

int main() {
 double hh = 0, mm = 12; //Исходное время в часах и минутах
 size_t s = 90; //Требуемый угол между стрелками в градусах, от 0 до 180
 size_t k = 0;
 for (size_t h = 0; h < 24; h++)
  for (size_t m = 0; m < 60; m++) {
   size_t u = calcAngle(h, m);
   if (abs((long)(s-u)) < 4)
    cout << setfill(' ') << setw(3) << ++k << " " <<
     setfill('0') << setw(2) << h << ":" << setw(2) << m << " " << u << endl;
     //Вывести счетчик, затем время с лидирующими нулями и угол
  }
 return 0;
}

5. Написать функцию для выделения памяти под массив целых значений с помощью malloc. Функция принимает два аргумента - указатель и размерость массива и имеет тип void, то есть, ничего не возвращает. После работы функции в указателе должен сохраниться адрес начала созданного массива.

#include <cstdlib>
#include <iostream>

void custom_malloc(int *&array, const size_t size) {
 array = static_cast<int*>(std::malloc(size * sizeof(int)));
}

int main() {
 int *array = nullptr;
 const int n = 10;
 custom_malloc (array, n);
 for (int i = 0; i < n; i++) {
  array[i] = i + 1;
  std::cout << array[i] << ' ';
 }
 return 0;
}

6. Заменить в заданном числе одну цифру так, чтобы новое число делилось на 3 и было максимально возможным. Алгоритм решения пытается быть быстрым, а можно ли лучше?

#include <iostream>
#include <numeric>
int main() {
 std::string n("371");
 int sum = std::accumulate(n.begin(), n.end(), 0,
  [](int i, int v) { return i + v - '0'; });
 int val = 3 - sum % 3;
 bool b = false;
 for (auto& it : n) {
  if (it - '0' + val > 9) continue;
  it += val;
  while (it - '0' + 3 <= 9) it += 3;
  b = true;
  break;
 }
 if (!b) n.back() -= val % 3 != 0 ? 3 - val : val;
 std::cout << n;
 return 0;
}

7. Нарисовать в текстовой консоли Windows цветной рисунок по образцу (попугай).

цветной попугай для консоли
цветной попугай для консоли

Мы интерпретировали рисунок как массив структур {x, y, c}, где (x,y) - столбец и строка в консоли (нумеруются с нуля), c - код цвета для консоли. Установлена кодовая страница DOS-866, чтобы пользоваться символом псевдографики-"квадратиком" с кодом 219.

#include <iostream>
#include <windows.h>
using namespace std;

void SetColor(int background, int text) {
 HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
 SetConsoleTextAttribute(hStdOut, (WORD)((background << 4) | text));
}

void gotoxy(int xp, int yp) {
 COORD new_xy; HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
 new_xy.X = xp; new_xy.Y = yp;
 SetConsoleCursorPosition(hStdOut, new_xy);
}

int main() {
 SetConsoleCP (866);
 SetConsoleOutputCP (866);
 SetColor (15,0);
 system("cls");
 system("mode con cols=80 lines=25");
 struct node { int x,y,c; };
 const node parrot[] = {
                                                                    { 6, 0, 0},{ 7, 0, 0},{ 8, 0, 0},{ 9, 0, 0},
                                              { 4, 1, 0},{ 5, 1, 0},{ 6, 1,12},{ 7, 1,12},{ 8, 1,12},{ 9, 1,12},{10, 1, 0},{11, 1, 0},
                                   { 3, 2, 0},{ 4, 2,12},{ 5, 2,12},{ 6, 2,12},{ 7, 2,12},{ 8, 2,12},{ 9, 2,12},{10, 2,12},{11, 2,12},{12, 2, 0},
                        { 2, 3, 0},{ 3, 3,12},{ 4, 3,12},{ 5, 3,12},{ 6, 3,12},{ 7, 3,12},{ 8, 3,12},{ 9, 3,12},{10, 3,12},{11, 3,12},{12, 3,12},{13, 3,0},
                        { 2, 4, 0},{ 3, 4,12},{ 4, 4,12},{ 5, 4,12},{ 6, 4,12},{ 7, 4,12},{ 8, 4,12},{ 9, 4,12},{10, 4,12},{11, 4,12},{12, 4,12},{13, 4,0},
             { 1, 5, 0},{ 2, 5,12},{ 3, 5,15},{ 4, 5,15},{ 5, 5,12},{ 6, 5,12},{ 7, 5,12},{ 8, 5,12},{ 9, 5,12},{10, 5,12},{11, 5,15},{12, 5,15},{13, 5,12},{14, 5, 0},
             { 1, 6, 0},{ 2, 6,15},{ 3, 6,15},{ 4, 6,15},{ 5, 6,15},{ 6, 6,12},{ 7, 6,12},{ 8, 6,12},{ 9, 6,12},{10, 6,15},{11, 6,15},{12, 6,15},{13, 6,15},{14, 6, 0},
             { 1, 7, 0},{ 2, 7,15},{ 3, 7,15},{ 4, 7, 0},{ 5, 7,15},{ 6, 7,12},{ 7, 7,12},{ 8, 7,12},{ 9, 7,12},{10, 7,15},{11, 7, 0},{12, 7,15},{13, 7,15},{14, 7, 0},
             { 1, 8, 0},{ 2, 8,12},{ 3, 8,15},{ 4, 8,15},{ 5, 8,15},{ 6, 8,12},{ 7, 8,12},{ 8, 8,12},{ 9, 8,12},{10, 8,15},{11, 8,15},{12, 8,15},{13, 8,12},{14, 8, 0},
                        { 2, 9, 0},{ 3, 9,12},{ 4, 9,12},{ 5, 9,15},{ 6, 9, 0},{ 7, 9, 0},{ 8, 9, 0},{ 9, 9, 0},{10, 9,15},{11, 9,12},{12, 9,12},{13, 9, 0},
                        { 2,10, 0},{ 3,10,12},{ 4,10,12},{ 5,10,12},{ 6,10, 0},{ 7,10, 0},{ 8,10, 0},{ 9,10, 0},{10,10,12},{11,10,12},{12,10,12},{13,10, 0},
                                   { 3,11, 0},{ 4,11,12},{ 5,11,12},{ 6,11,12},{ 7,11, 0},{ 8,11, 0},{ 9,11,12},{10,11,12},{11,11,12},{12,11,0},
                        { 2,12, 0},{ 3,12,14},{ 4,12,12},{ 5,12,12},{ 6,12,12},{ 7,12,12},{ 8,12,12},{ 9,12,12},{10,12,12},{11,12,12},{12,12,14},{13,12, 0},
             { 1,13, 0},{ 2,13, 1},{ 3,13,14},{ 4,13,12},{ 5,13,12},{ 6,13,12},{ 7,13,12},{ 8,13,12},{ 9,13,12},{10,13,12},{11,13,12},{12,13,14},{13,13, 1},{14,13, 0},
             { 1,14, 0},{ 2,14, 1},{ 3,14, 1},{ 4,14,12},{ 5,14,12},{ 6,14,12},{ 7,14,12},{ 8,14,12},{ 9,14,12},{10,14,12},{11,14,12},{12,14, 1},{13,14, 1},{14,14, 0},
             { 1,15, 0},{ 2,15, 1},{ 3,15, 1},{ 4,15,12},{ 5,15,12},{ 6,15,12},{ 7,15,12},{ 8,15,12},{ 9,15,12},{10,15,12},{11,15,12},{12,15, 1},{13,15, 1},{14,15, 0},
             { 1,16, 0},{ 2,16, 1},{ 3,16, 0},{ 4,16,12},{ 5,16,12},{ 6,16,12},{ 7,16, 0},{ 8,16, 0},{ 9,16,12},{10,16,12},{11,16,12},{12,16, 0},{13,16, 1},{14,16, 0},
  { 0,17, 6},{ 1,17, 6},{ 2,17, 0},{ 3,17, 6},{ 4,17, 0},{ 5,17, 0},{ 6,17, 0},{ 7,17, 6},{ 8,17, 6},{ 9,17, 0},{10,17, 0},{11,17, 0},{12,17, 6},{13,17, 0},{14,17, 6},{15,17, 6},
  { 0,18, 6},{ 1,18, 6},{ 2,18, 6},{ 3,18, 6},{ 4,18, 6},{ 5,18, 6},{ 6,18, 6},{ 7,18, 6},{ 8,18, 6},{ 9,18, 6},{10,18, 6},{11,18, 6},{12,18, 6},{13,18, 6},{14,18, 6},{15,18, 6},
  { 0,19, 6},{ 1,19, 6},{ 2,19, 6},{ 3,19, 6},{ 4,19, 6},{ 5,19, 6},{ 6,19, 6},{ 7,19, 6},{ 8,19, 6},{ 9,19, 6},{10,19, 6},{11,19, 6},{12,19, 6},{13,19, 6},{14,19, 6},{15,19, 6},
                                                         { 5,20, 0},{ 6,20,12},{ 7,20,12},{ 8,20,12},{ 9,20,12},{10,20, 0},
                                                                    { 6,21, 0},{ 7,21,12},{ 8,21,12},{ 9,21, 0}

 };
 int size = sizeof(parrot)/sizeof(parrot[0]);
 unsigned char fill = 219;
 for (int i=0; i < size; i++) {
  SetColor(15, parrot[i].c);
  gotoxy (parrot[i].x, parrot[i].y);
  cout << fill;
 }
 SetColor(15,0);
 gotoxy (0,22);
 system("pause");
 return 0;
}

Как насчёт более удобного формата данных для этой задачи? Например, я бы посмотрел в сторону Tiled map editor с последующей интерпретацией его файлов.

8. Написать функцию, которая принимает в качестве аргументов другую функцию и положительное целое число. Последняя функция выполняется количество раз, равное целому числу.

#include <iostream>

template <typename Function>
void repeat(Function f, unsigned int n) {
 for (unsigned int i = n; 0 < i; i--)
  f();
}

void example() {
 std::cout << "Example\n";
}

int main() {
 repeat(example, 4);
 repeat([] {std::cout << "Example\n"; }, 4); //работает начиная с C++11
 return 0;
}

9. Написать функцию, дублирующую заданную первым аргументом строку std::string указанное вторым аргументом количество раз.

#include <string>
#include <iostream>

std::string repeat(const std::string& word, int times) {
 std::string result;
 result.reserve(times * word.length()); 
  //избегать повторного перераспределения памяти
 for (int a = 0; a < times; a++)
  result += word;
 return result;
}

int main() {
 std::cout << repeat("Foo", 5) << std::endl;
 return 0;
}

10. Строка с повторами. Задана std::string, состоящая из символов нулей и единиц. Определить, является ли она строкой, в которой последовательность первых N символов повторяется как минимум дважды. Исходная строка может быть усечена справа до размерности, соответствующей двум или более вхождениям подстроки. В случае неоднозначности учитывается самая длинная из возможных подстрок, например, в строке "1010101010" дважды повторяется фрагмент "1010", но не пять раз фрагмент "10".

#include <iostream>
#include <string>
#include <vector>
#include <regex>

bool is_repstring(const std::string& teststring, std::string& repunit) {
 std::string regex("^(.+)\\1+(.*)$");
 std::regex e(regex);
 std::smatch what;
 if (std::regex_match(teststring, what, e)) {
  std::string firstbracket(what[1]);
  std::string secondbracket(what[2]);
  if (firstbracket.length() >= secondbracket.length() &&
   firstbracket.find(secondbracket) != std::string::npos) {
   repunit = firstbracket;
  }
 }
 return !repunit.empty();
}

int main() {
 std::vector<std::string> teststrings{ 
  "1001110011", 
  "1110111011", 
  "1010101010", 
  "1111111111", 
  "0100101101",
  "0100100",
  "101",
  "00",
  "1" 
 };
 std::string theRep;
 for (std::string myString : teststrings) {
  std::cout << myString << ": ";
  if (is_repstring(myString, theRep)) std::cout << " YES (" << theRep << ")";
  else std::cout << " NO";
  std::cout << std::endl;
  theRep.clear();
 }
 return 0;
}

Результаты вывода программы:

1001110011:  YES (10011)
1110111011:  YES (1110)
1010101010:  YES (1010)
1111111111:  YES (11111)
0100101101:  NO
0100100:  YES (010)
101:  NO
00:  YES (0)
1:  NO

31.10.2021, 10:43 [660 просмотров]


теги: список c++ алгоритм

К этой статье пока нет комментариев, Ваш будет первым