БлогNot. 13 не пригодившихся задач за апрель 2023

13 не пригодившихся задач за апрель 2023

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

Все задачи выполнялись в консоли Visual Studio 2019 или 2022 из пустого проекта с единственным добавленным файлом Source.cpp.

Спрашивали про мини-задачи #4 (считалка), #11 (площадь пятиугольника как сумма площадей трёх треугольников) и #13 (точка на плоскости внутри треугольника). Если ещё что-то добавится, пополню эту заметку.

1. Не применяя массивов или иных контейнеров, сгенерировать миллион случайных чисел со значением 0 или 1 и найти длину максимальной цепочки одинаковых значений.

#include <iostream>
#include <cstdlib>
#include <ctime>

int main() {
 int cnt = 1, max = 1, prev = -1, curr;
 srand(time(NULL)); //инициализировать генератор случайных чисел
 for (int x = 0; x < 1e6; x++) {
  curr = rand() % 2; //0 или 1
  if (curr == prev) {
   cnt++;
   if (cnt > max) max = cnt;
  }
  else cnt = 1;
  prev = curr;
 }
 std::cout << max;
 return 0;
}

2. Заполнить статический массив случайными числами из диапазона значений [0;99] и найти среднее арифметическое этих чисел.

#include <iostream>
#include <iomanip>
#include <cstdlib> /* srand, rand */
#include <ctime> /* time */

int main() {
 const int n = 5; 
  //размерность статического массива всегда задаем константой
 int arr[n];
 double sum = 0;
 srand(time(NULL));
  //инициализировать генератор случайных чисел
 for (int i = 0; i < n; i++) {
  arr[i] = rand() % 100; //число от 0 до 99
  std::cout << arr[i] << ' ';
  sum += arr[i];
 }
 std::cout << std::endl << "Average is " << 
  std::fixed << std::setprecision(2) << (sum / n);
 return 0;
}

3. Решить нелинейное уравнение методом простых итераций. Здесь f(x) - исходная функция из уравнения f(x) = 0, phi(x) - функция из уравнения, приведённого к виду x = phi(x).

/* Пример численного решения уравнения методом
 простых итераций*/
#include <iostream>
#include <cmath>

double f(double x) {
 return 2 * pow(x, 3) - 3 * pow(x, 2) + 5 * x - 3;
}

double phi(double x) {
 return (-2 * pow(x, 3) + 3 * pow(x, 2) + 3) / 5.;
}

int main() {
 //исходное уравнение: f(x) = 0: 2*x^3 - 3*x^2 + 5*x - 3 = 0
 //эквивалентная форма x = phi(x): x = (- 2*x^3 + 3*x^2 + 3) / 5
 double xn0 = 1, xn, eps = 1e-12;
 int n = 0; //сходимость может зависеть от начальной точки xn0!
 do { //метод простых итераций:
  xn = phi(xn0);
  if (abs(xn - xn0) < eps || n > 1000) break;
  xn0 = xn;
  n++;
 } while (1);
 std::cout.precision(15);
 std::cout << "x=" << xn << ", " << n << " step(s)" <<
  std::endl << "check f(x)=" << std::fixed << f(xn);
 return 0;
}

4. Детская считалка. n человек стоят по кругу, считалка состоит из k слов, ведущий начинает отсчёт слов с себя. Если он выходит, ведущим становится следующий стоящий против часовой стрелки. Мальчик Вася такой умный, что всегда может заранее сказать, кто выйдет, а Вы? Люди нумеруются также с единицы против часовой стрелки, начиная с ведущего.

#include <iostream>

int main() {
 int k = 11, n = 4;
 while (n > 1) {
  std::cout << (k % n == 0 ? n : k % n) //формула для "выходящего" предельно проста
   << " from "<< n << std::endl;
  n--;
 }
 return 0;
}

5. Взять методом средних прямоугольников определённый интеграл в пределах интегрирования от 0 до π для f(x) = sin(x), шаг по x равен одной сотой.

#include <iostream>
#define _USE_MATH_DEFINES
#include <math.h>

double f(double x) { return sin(x); }

int main() {
 double a = 0, b = M_PI, dx = 0.01, s = 0;
 for (double x = a; x <= b; x += dx) {
  s += dx * f(x + dx / 2.);
 }
 std::cout << s;
 return 0;
}

6. Решить СЛАУ из 2 уравнений методом Крамера. Проверить найденное решение. Вместо матрицы a[n][m] использовать в подпрограммах "псевдоматрицу" - вектор длиной n*m, для которого обращение к элементу a[i][j] соответствует обращению к a[m*i+j].

/*
 Решение СЛАУ вида
 a[1][1]*x[1] + a[1][2]*x[2] = b[1]
 a[2][1]*x[1] + a[2][2]*x[2] = b[2]
 размерностью 2x2 методом Крамера.
 Используем "псевдоматрицу" - массив a[n][m]
 интерпретируем как a[n*m]
*/
#include <iostream>
#include <iomanip>
#include <cmath>

double det2x2(double* a) {
 //Определитель матрицы 2x2 - без проверки данных!
 return a[0] * a[3] - a[1] * a[2];
}

double* replace_column(int n, int m, double* a, int c, double* b) {
 //Замена столбца c в матрице a[n][m] на вектор b - без проверки данных!
 double* new_a = new double[n * m];
 if (!new_a) return nullptr;
 for (int i = 0; i < n; i++)
  for (int j = 0; j < m; j++)
   new_a[m * i + j] = (j == c ? b[i] : a[m * i + j]);
 return new_a;
}

double* mmul(int n, int m, int p, double* a, double* b) {
 //a[n][m] * b[m][p] = c[n][p]
 double* c = new double[n * p];
 if (!c) return nullptr;
 for (int i = 0; i < n; i++) {
  for (int k = 0; k < p; k++) {
   c[p * i + k] = 0;
   for (int j = 0; j < m; j++)
    c[p * i + k] += a[m * i + j] * b[p * j + k];
  }
 }
 return c;
}

int main() {
 const int n = 2;
 //Замените статическое определение вводом данных
 double a[n * n] = {
  1.5,-2.5,
  0.7, 3.4
 };
 double b[n] = { 1, 2 };
 //Проверям существование решения
 double det = det2x2(a);
 if (det == 0) {
  std::cout << "No solution, det(A) = 0";
  return -1;
 }
 //Считаем и выводим решение
 double* a0 = replace_column(n, n, &a[0], 0, &b[0]);
 double* a1 = replace_column(n, n, &a[0], 1, &b[0]);
 double det0 = det2x2(a0), det1 = det2x2(a1);
 double x[n];
 x[0] = det0 / det;
 x[1] = det1 / det;
 std::cout << "Solution: ";
 std::cout.precision(3);
 for (int j = 0; j < n; j++)
  std::cout << std::setw(8) << std::fixed << x[j];
 std::cout << std::endl;
 //Проверяем решение
 double* new_b = mmul(n, n, 1, a, x);
 std::cout << "Errors:   ";
 for (int j = 0; j < n; j++)
  std::cout << std::setw(8) << std::fixed << abs(b[j] - new_b[j]);
 delete[] a1;
 delete[] a0;
 delete[] new_b;
 return 0;
}

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

#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <ctime>
#include <chrono>

class Timer {
 std::chrono::high_resolution_clock::time_point start;
public:
 Timer() {
  start = std::chrono::high_resolution_clock::now();
 }
 double stop() {
  std::chrono::high_resolution_clock::time_point end =
   std::chrono::high_resolution_clock::now();
  std::chrono::duration <double>
   time_span = std::chrono::duration_cast <std::chrono::duration<double>>(end - start);
  return time_span.count();
 }
};

template <typename T> void fill_array(const int n, T a[], T low, T hi) {
 srand((unsigned int)time(NULL));
 for (int i = 0; i < n; i++)
  a[i] = low + rand() % (hi - low + 1);
}

template <typename T> void swap(T& a, T& b) {
 T c = a; a = b; b = c;
}

template <typename T> void type_array(const int n, T a[]) {
 std::cout << std::fixed;
 for (int i = 0; i < n; i++)
  std::cout << std::setw(5) << a[i];
 std::cout << std::endl;
}

void selection_sort(const int n, int a[]) {
 int min, imin, i, j;
 for (i = 0; i < n; i++) {
  min = a[i]; imin = i;
  for (j = i + 1; j < n; j++) {
   if (a[j] < min) {
    min = a[j]; imin = j;
   }
  }
  swap <int >(a[imin], a[i]);
 } 
}

void bubble_sort(const int n, int a[]) {
 int i, j;
 for (i = 0; i < n - 1; i++) { //внешний цикл отвечает за номер прохода
  for (j = n - 1; j > i; j--) { //внутренний - за перебор элементов в одном проходе
   if (a[j - 1] > a[j]) swap <int >(a[j-1], a[j]);
  }
 }
}

void inserting_sort(const int n, int a[]) {
 int i, j, temp;
 for (i = 1; i < n; i++) {
  temp = a[i];
  for (j = i; j > 0 && temp < a[j - 1]; j--) {
   a[j] = a[j - 1];
  }
  a[j] = temp;
 }
}

void refresh() {
 std::cin.clear();
 std::cin.ignore(100, '\n');
}

int main() {
 int n = 10000;
 int* a = new int[n];
 if (!a) {
  std::cout << "No memory!" << std::endl;
  return -1;
 }
 double time;
 bool show = true;
 do {
  std::cout << "Select the action:" << std::endl <<
   "1 - Selection sorting" << std::endl <<
   "2 - Bubble sorting" << std::endl <<
   "3 - Inserting sorting" << std::endl <<
   "4 - New array size (now is " << n << ")" << std::endl <<
   "5 - Show sorted: now is " << (show ? "on" : "off") << ")" << std::endl <<
   "0 - Exit" << std::endl;
  char choice;
  std::cin >> choice;
  refresh();
  switch (choice) {
  case '1':
  case '2':
  case '3':
   fill_array(n, a, -n, n);
   { //только чтобы описать внутри таймер
    Timer t;
    switch (choice) {
    case '1': selection_sort(n, a); break;
    case '2': bubble_sort(n, a); break;
    case '3':  inserting_sort(n, a); break;
    }
    time = t.stop();
   }
   if (show) type_array(n, a);
   std::cout << "time: " << std::fixed << time << " sec." << std::endl;
   break;
  case '4':
   do {
    std::cout << "Current size is " << n << std::endl <<
     "Put new size (integer >99): ";
    std::cin >> n;
    if (!std::cin.good() || n < 100) {
     refresh(); continue;
    }
    else break;
   } while (1);
   if (a) {
    delete[] a; a = nullptr;
    a = new int[n];
    if (!a) {
     std::cout << "No memory!" << std::endl;
     return -1;
    }
   }
   break;
  case '5': show = !show; break;
  case '0': exit(0);
  default:
   std::cout << "Bad action, repeat it, please" << std::endl;
   break;
  }
 } while (1);
 return 0;
}

Расширенная версия программки и теория есть здесь.

8. Функция y=sin(x) на интервале по x = [0;π/2] хорошо приближается разложением y0 = x - x3/3! + x5/5!. Напишите программу, которая для заданного значения аргумента x подсчитывает по этой формуле y0 и сравнивает его с точным значением, вычисленным с помощью стандартной функции.

#include <iostream>
#include <iomanip>        //Чтобы были манипуляторы ввода
#define _USE_MATH_DEFINES //Чтобы была константа для 
#include <math.h>         //числа "Пи" и математика
using namespace std;

int main() {
 double x = M_PI / 10, //x от 0 до Пи/2
  y = sin(x),
  y0 = x - pow(x, 3) / 6 + pow(x, 5) / 120;
 cout << "   y=" << setprecision(12) << y <<
  endl << "my y=" << y0 <<
  endl << "diff=" << fixed << abs(y - y0);
 return 0;
}

9. Напишите программу, которая алгоритмически определяет день недели для произвольной даты dd.mm.yyyy, корректность вводимой даты можно не проверять.

#include <iostream>
using namespace std;

int main() {
 unsigned int d, m, y, wd;

 cout << "Input d m yyyy: ";
 cin >> d >> m >> y;
 if (!cin) {
  cout << "Get me correct date, please";
  return -1;
 }

 if (m < 3) {
  m += 12; y--;
 }
 int c = y / 100;
 y %= 100;
 wd = (d + 13*(m+1)/5 + y + y/4 +c/4 + 5*c) % 7;
 cout << "Weekday is " << wd << endl;
 cout << "[0-Sa, 1-Su, 2-Mo, 3-Tu, 4-We, 5-Th, 6-Fr]";
 return 0;
}

10. Напечатать в консоли простейшую шахматную доску и проверить, находится ли размещённый на ней король под боем хотя бы одной из двух ладей.

#include <iostream>
#include <iomanip>

const int size = 8;
char b[size + 1][size + 1]; //нумеруем с единицы

void init() {
 for (int y = 1; y <= size; y++)
  for (int x = 1; x <= size; x++)
   b[x][y] = ' ';
}

void print() {
 for (int y = 1; y <= size; y++) {
  std::cout << std::endl;
  for (int x = 1; x <= size; x++) {
   char c = (x + y) % 2 == 0 ? ' ' : '*';
   if (b[x][y] != ' ') c = b[x][y];
   std::cout << c;
  }
 }
}

bool set(char f, int x, int y) {
 if (x < 1 || x > size || y <1 || y >size) return false;
 if (b[x][y] != ' ') return false;
 b[x][y] = f;
 return true;
}

int main() {
 int r1x = 8, r1y = 1, r2x = 4, r2y = 4, k1x = 8, k1y = 4;
 init();
 if (!set('R', r1x, r1y) ||
  !set('R', r2x, r2y) ||
  !set('k', k1x, k1y)) {
  std::cout << "Bad position"; return -1;
 }
 print();
 std::cout << std::endl << "King is " <<
  (k1x == r1x || k1x == r2x || k1y == r1y || k1y == r2y ?
   "" : "not ") << "checked";
 return 0;
}

11. Найти площадь пятиугольника как сумму площадей трёх треугольников.

#include <iostream>
#include <cmath>

// Функция для вычисления сторон 
double Distance(double x1, double x2, double y1, double y2) {
 return std::hypot(x2 - x1, y2 - y1);
}

//Функция для площади треугольника (Герона)
double Stri(double ab, double bc, double cd) {
 double p = (ab + bc + cd) / 2;
 return std::sqrt(p * (p - ab) * (p - bc) * (p - cd));
}

int main() {
 // Значения для координат.
 double x1 = 2.5, y1 = 1.5;
 double x2 = 1.3, y2 = 2.1;
 double x3 = 3.1, y3 = 2.9;
 double x4 = 5.4, y4 = 2.5;
 double x5 = 4.9, y5 = 1.8;

 // Расчет сторон:
 double ab = Distance(x1, y1, x2, y2);
 double bc = Distance(x2, y2, x3, y3);
 double cd = Distance(x3, y3, x4, y4);
 double de = Distance(x4, y4, x5, y5);
 double ea = Distance(x5, y5, x1, y1);
 double da = Distance(x4, y4, x1, y1);
 double db = Distance(x4, y4, x2, y2);

 // Расчет площадей:
 double Sabd = Stri(ab, db, da);
 double Sade = Stri(bc, cd, db);
 double Sbcd = Stri(ea, da, de);
 double S5 = Sabd + Sade + Sbcd;

 // Вывод на экран:
 std::cout << "S(ABD)= " << Sabd << std::endl;
 std::cout << "S(ADE)=" << Sade << std::endl;
 std::cout << "S(BCD)=" << Sbcd << std::endl;
 std::cout << "S(ABCDE)=" << S5 << std::endl;
}

Картинка с графиком есть в этой заметке.

12. Найти значение числа π с помощью ряда Мадхавы. Реализовать версии программы с критерием точности |u|≤&eps;, где u - очередное слагаемое ряда и с заданным предельным количеством итераций n.

Ряд Мадхавы, он же ряд Лейбница - старинный способ вычисления числа Пи.

Если точность задана константой eps (ниже 10-15 смысла задавать нет):

#include <iostream>
#include <iomanip>
#include <cmath>
#define _USE_MATH_DEFINES
#include <math.h>


int main() {
 double eps = 1e-15, a = 1, u = 1, pi = 1;
 int n = 0;
 while (abs(u) > eps) {
  n++;
  a *= -3;
  u = 1 / a / (2 * n + 1);
  pi += u;
 }
 pi *= sqrt(12);

 std::cout.precision(15);
 std::cout << "pi = " << std::fixed << pi << 
  std::endl << "pi = " << M_PI << " (standard)";
 return 0;
}

Если задано количество итераций n:

#include <iostream>
#include <iomanip>
#include <cmath>
#define _USE_MATH_DEFINES
#include <math.h>


int main() {
 double a = 1, u = 1, pi = 0;
 int n = 1000000, k = 0;
 do {
  pi += u;
  k++;
  a *= -3;
  u = 1 / a / (2 * k + 1);
 } while (k <= n);
 pi *= sqrt(12);

 std::cout.precision(15);
 std::cout << "pi = " << std::fixed << pi << 
  std::endl << "pi = " << M_PI << " (standard)";
 return 0;
}

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

#include <iostream>

//Площадь треугольника с вершинами (x1, y1), (x2, y2), (x3, y3)
double area(double x1, double y1, double x2, double y2, double x3, double y3) {
 return abs((x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2)) / 2.0);
}

//Лежит ли точка P(x,y) внутри треугольника A(x1, y1), B(x2, y2), C(x3, y3)
bool isInside(double x1, double y1, double x2, double y2, double x3, 
              double y3, double x, double y) {
 double A = area(x1, y1, x2, y2, x3, y3); //ABC
 double A1 = area(x, y, x2, y2, x3, y3); //PBC
 double A2 = area(x1, y1, x, y, x3, y3); //PAC
 double A3 = area(x1, y1, x2, y2, x, y); //PAB
 return (A == A1 + A2 + A3);
}

int main() {
 //P в треугольнике A(0, 0), B(4, 0), C(4, 3)
 double P[2] = { 2.5, 2};
 std::cout << (isInside(0, 0, 4, 0, 4, 3, P[0], P[1]) ? "Yes": "No");
 P[0] = 3;
 std::cout << std::endl << (isInside(0, 0, 4, 0, 4, 3, P[0], P[1]) ? "Yes" : "No");
 return 0;
}

13.04.2023, 10:38 [310 просмотров]


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

показать комментарии (1)