БлогNot. 17 не пригодившихся задач за май 2021

17 не пригодившихся задач за май 2021

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

Среди постановок есть как совсем простые, так и чуть поинтереснее.

1. Из каждого элемента вектора вычесть среднее арифметическое его элементов.

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <numeric>
using namespace std;

int main() {
 vector <double> v {1, 2, 3, 4};
 cout << "Source= ";
 copy(v.begin(), v.end(), ostream_iterator<double>(cout, " "));
 
 double avg = accumulate(v.begin(), v.end(), 0.0) / v.size();
 cout << endl << "Avg= " << avg << endl;
 
 transform(v.begin(), v.end(), v.begin(), [&](double x) { return x - avg; });
 //или for_each (v.begin(), v.end(), [&](double x) { x -= avg; });

 cout << "Destination= ";
 copy (v.begin(), v.end(), ostream_iterator<double>(cout, " "));

 return 0;
}

2. Сделать копию стека St без отрицательных элементов. Результат – новый стек St1.

#include <QStack>
#include <QtAlgorithms>
#include <QDebug>

int main() {
  QStack <int> St, St1;
  St << 1 << -2 << 3 << -3 << 2;
  qDebug() << St;
  std::copy_if (St.begin(), St.end(), std::back_inserter(St1), [](int i){ return i>=0; } );
  qDebug() << St1;
  return 0;
}

Сделано в Qt, там удобнее запись элементов в стек оператором << и вывод с помощью qDebug.

3. Записать в бинарный файл N = 10 целых чисел с консоли. Найти сумму максимального и минимального чисел, найденным значением заменить первую и предпоследнюю компоненты файла. Сумму, исходный файл и файл после замены вывести в консоль.

#include <cstdlib>
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;

template <typename T> vector <T> read(const char* fname) {
 vector <T> v;
 ifstream f(fname, ios::binary);
 if (!f) {
  cout << "Can't open " << fname << " to read data"; exit(2);
 }
 T val;
 while (!f.read((char*)&val, sizeof(T)).eof()) {
  v.push_back (val);
 }
 f.close();
 return v;
}

int main() {
 const int n = 10;
 vector <int> v;
 
 int val;
 cout << endl;
 for (size_t i = 0; i < n; i++) {
  do {
   cout << "Type item " << (i+1) << ": ";
   cin >> val;
   if (cin.good()) break;
   cin.clear();
   cin.ignore(INT_MAX, '\n');
  } while (1);
  v.push_back (val);
 }

 ofstream f("1.dat", ios::binary);
 if (!f) {
  cout << "Can't open 1.dat to write"; exit(1);
 }
 f.write((char*)&v[0], v.size() * sizeof(int));
 f.close();

 v.clear();
 v = read <int> ("1.dat");
 cout << endl << "Read source file: ";
 copy(v.begin(), v.end(), ostream_iterator <int>(cout, " "));

 int sum = *min_element(v.begin(), v.end()) + *max_element(v.begin(), v.end());
 cout << endl << "Sum= " << sum;

 fstream f2("1.dat", ios::binary | ios::in | ios::out);
 f2.seekp(0, ios_base::beg);
 f2.write((char*)&sum, sizeof(int));
 f2.seekp((v.size()-2)* sizeof(int), ios_base::beg);
 f2.write((char*)&sum, sizeof(int));
 f2.close();
 
 v.clear();
 v = read <int>("1.dat");
 cout << endl << "Read changed file: ";
 copy(v.begin(), v.end(), ostream_iterator <int>(cout, " "));
 
 return 0;
}

Тестовый прогон:

Type item 1: 1
Type item 2: 2
Type item 3: 3
Type item 4: 4
Type item 5: 5
Type item 6: 6
Type item 7: 7
Type item 8: 8
Type item 9: 9
Type item 10: вводим что попало вместо числа, такое не пройдёт
Type item 10: 10

Read source file: 1 2 3 4 5 6 7 8 9 10
Sum= 11
Read changed file: 11 2 3 4 5 6 7 8 11 10

4. В конце заданной строки дописать символы подчёркивания "_", доведя длину строки до 25 символов.

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

int main() {
 const size_t len = 25;
 string s("I'm a string");
 size_t my_len = s.length();
 if (my_len < len) s.insert(s.end(), len - my_len, '_');
 cout << s;
 return 0;
}

5. Сформировать контейнер q, включив в него по одному разу элементы, которые входят в одну и только одну из очередей q1 и q2 (Qt).

#include <QDebug>
#include <QQueue>
#include <QList>
#include <QSet>

int main() {
 QQueue <int> q1, q2;
 q1 << 1 << 3 << 2 << 4 << -5;
 q2 << 1 << 1 << 8 << 4 << -5 << 7 << 7;
 QSet <int> q0 = q1.toSet().intersect(q2.toSet());
  //почистили от дублей очереди и пересекли их
 QList <int> q = q1.toSet().subtract(q0).toList() +
  q2.toSet().subtract(q0).toList();
  //вычли пересечение из каждого из множеств и
  //сложили их
 qDebug() << q;
}

6. Реализовать вычисление арифметического среднего, произведения, минимума, максимума из элементов вещественного массива с размерностью, не превышающей заданной. Использовать шаблонную функцию для ввода через cin значения числового типа с проверкой корректности ввода.

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

template <typename T> T getVal (const char *msg, T min, T max) {
 T val;
 do {
  cout << endl << msg; cout.precision (2);
  cin >> val;
  if (!cin.good()) {
   cin.clear();
   cin.ignore (INT_MAX, '\n');
   continue;
  }
  if (val < min || val > max) {
   cout << "Введите значение от " << fixed << min << " до " << fixed << max;
   continue;
  }
  return val;
 } while (1);
}

int main() {
 SetConsoleCP(1251); SetConsoleOutputCP(1251); //windows.h
 const int nmax = 100; //максимальная размерность
 double a[nmax] = {0};
 int n; //реальная размерность
 n = getVal ("N=", 2, nmax);
 double summa = 0., max = -DBL_MAX, min = DBL_MAX, pr = 0.;
 char buf[80];
 for (int i = 0; i < n; i++) {
  sprintf(buf, "A[%d]=", i+1);
  a[i] = getVal(buf, -1e3, 1e3);
  summa += a[i];
  if (a[i] > max) max = a[i];
  if (a[i] < min) min = a[i];
  if (a[i] != 0.) pr = (pr == 0 ? a[i] : pr * a[i]);
 }
 cout << endl << "AVG=" << (summa / n) << " MAX=" << max <<
  " MIN=" << min << " PRD=" << pr;
 cin.get(); return 0;
}

7. Обойти матрицу размерности N x N по спирали против часовой стрелки начиная с правого верхнего угла и заполнить её числами 1, 2, ..., N2

#include <iostream>
#include <iomanip>
using namespace std;
int main() {
 const int n = 5;
 int spiral[n][n];
 int value = 1;
 int minCol = 0;
 int maxCol = n - 1;
 int minRow = 0;
 int maxRow = n - 1;
 while (value <= n * n) {
  for (int i = maxCol ; i >= minCol; i--) spiral[minRow][i] = value++; //влево
  for (int i = minRow + 1; i <= maxRow; i++) spiral[i][minCol] = value++; //вниз
  for (int i = minCol + 1; i <= maxCol; i++) spiral[maxRow][i] = value++; //вправо
  for (int i = maxRow - 1; i > minRow; i--) spiral[i][maxCol] = value++; //вверх
  minCol++;
  minRow++;
  maxCol--;
  maxRow--;
 }
 for (int i = 0; i < n; i++) {
  for (int j = 0; j < n; j++) cout << setw(4) << spiral[i][j];
  cout << endl;
 }
 return 0;
}

8. Создать класс Vector для работы с векторами на плоскости, содержащий следующие члены класса: поля double x, у; функции или операторы, позволяющие вывести на экран вектор, вычислить длину вектора, сравнить два вектора на равенство.

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

class Vector {
 double x,y;
 public:
 Vector (double _x=0., double _y = 0.) : x(_x), y(_y) {}
 Vector (const Vector &right) { x=right.x; y=right.y; }
 Vector& operator = (const Vector& right) {
  if (this != &right) { x = right.x; y = right.y; }
  return *this;
 }
 friend ostream& operator << (ostream& os, Vector& _data) {
  os.precision(3);
  os << endl << "(" << setw(8) << fixed << _data.x << "," << 
   setw(8) << fixed << _data.y << ")";
  return os;
 }
 double length() { return sqrt(pow(x,2)+pow(y,2)); }
 bool operator == (const Vector& right) {
  return x==right.x && y==right.y;
 }
};

int main() {
 Vector x(1,1);
 cout << x;
 Vector y = x;
 cout << y;
 cout << endl << (x==y);
 cout << endl << x.length();
 Vector z;
 z = x = y;
 cout << z;
 return 0;
}

9. Объявить целочисленную квадратную матрицу порядка N. Заполнить матрицу выше главной диагонали единицами, на главной диагонали - нулями, а ниже неё – двойками. Вывести матрицу на экран.

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

int main() {
 const int n = 5;
 int a[n][n];
 for (int i = 0; i < n; i++) {
  for (int j = 0; j < n; j++) {
   if (i < j) a[i][j] = 1; 
   else if (i > j) a[i][j] = 2;
   else a[i][j] = 0;
   cout << setw(4) << a[i][j];
  }
  cout << endl;
 }
 return 0;
}

10. По дате, заданной натуральными значениями "день", "месяц" и "год" (предполагается, что данные заданы корректно), определить и вывести дату предыдущего дня.

#include <iostream>
using namespace std;

int main() {
 int d = 27, m = 5, y = 2021; //день, месяц, год
 int md[] = {31,28,31,30,31,30,31,31,30,31,30,31}; //продолжительность месяцев
 if (y%400==0 || y%4==0 && y%100!=0) md[1]++; //29 февраля для високосных
 //контроля правильности данных нет
 if (d > 1) d--;
 else {
  if (m > 1) {
   m--; d = md[m-1];
  }
  else {
   d = 31; m = 12; y--; //с новым годом, итить
  }
 }
 cout << d << "." << m << "." << y;
 return 0;
}

11. Дано 100 первых натуральных чисел. Напечатать их по 12 в строке.

#include <iostream>
#include <iomanip>

int main() {
 for (int i = 0, cnt = 1; i < 100; i++, cnt++) {
  std::cout << std::setw(4) << (i + 1);
  if (cnt % 12 == 0) { cnt = 0;  std::cout << std::endl; }
 }
 return 0;
}

12. Найти количество элементов матрицы, расположенных между первым минимальным и последним максимальным элементами (при последовательном построчном обходе элементов матрицы).

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

int main() {
 const int n = 3, m = 4;
 int b[n][m] = {
  {1,2,0,3},
  {4,5,6,9},
  {7,9,8,1}
 };
 int imin1 = 0, jmin1 = 0, imaxn = 0, jmaxn = 0;
 for (int i = 0; i < n; i++) {
  for (int j = 0; j < m; j++) {
   if (b[i][j] < b[imin1][jmin1]) { imin1 = i; jmin1 = j; }
   if (b[i][j] >= b[imaxn][jmaxn]) { imaxn = i; jmaxn = j; }
  }
 }
 int nmin = imin1 * m + jmin1, nmax = imaxn * m + jmaxn;
 if (nmin > nmax) cout << (nmin - nmax - 1);
 else cout << (nmax - nmin - 1);
 return 0;
}

Но вообще в такой задаче я бы сразу матрицу делал как

const int n = 3, m = 3;
 int a[n * m] = {
  1,2,3,
  4,5,6,
  7,8,9
 };

и обошелся одним циклом.

13. Извлечь из строки std::string все лексемы, являющиеся допустимой записью вещественных чисел и найти сумму этих чисел.

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

int main() {
 string s("Hello, 123 , I'm a 1e3 test 1.5 "), next;
  //              123         1000     1.5
 istringstream iss(s);
 double sum = 0;
 size_t pos = 0;
 while (iss >> next) {
  try {
   double f = stof(next, &pos);
   if (pos == next.size()) {
    sum += f;
   }
  }
  catch (invalid_argument const&) {
   continue;
  }
 }
 cout << "Sum=" << fixed << sum;
 return 0;
}

14. Написать простейший класс Rectangle, содержащий следующие члены класса: поля double а, b; функции, позволяющие вывести на экран информацию о прямоугольнике, рассчитать периметр прямоугольника, рассчитать площадь прямоугольника, установить длины сторон прямоугольника, установить, является ли данный прямоугольник квадратом.

#include <iostream>
using namespace std;

class Rectangle {
 double a,b;
 public:
  Rectangle (double _a = 0., double _b = 0.) : a(_a), b(_b) {}
  void show() { cout << endl << a << ", " << b; }
  double perimeter() { return 2 * a + 2 * b; }
  double square() { return  a * b; }
  void set (double _a = 0., double _b = 0.) { a = _a; b = _b; }
  bool is_square () { return a==b; } 
   //вообще-то, вещественные числа так некорректно сравнивать, 
   //но пугать вариантами сравнения "с точностью до..." не будем
};

int main() {
 Rectangle r(4,3);
 r.show();
 cout << endl << "p=" << r.perimeter() << ", s=" << r.square();
 r.set(5,5);
 r.show();
 cout << endl << "Is square now? " << r.is_square();
 return 0;
}

15. Написать консольную программу для решения квадратных уравнений со следующими возможностями:

  • возможность последовательно решить любое количество уравнений, проверка корректности вводимых данных;
  • учёт всех особых случаев, таких как тождество, несовместное уравнение, линейное уравнение, единственный вещественный корень, комплексные корни и т.п.
  • корректный вывод результатов, исключающий, например, "-0" и другие проблемы, связанные с обработкой вещественных чисел.

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

//сравнение двух значений double с допустимой погрешностью eps
bool equal(double a, double b, double eps) { return abs(a-b) < eps; }

//замена нулём значений меньше eps, чтобы не печаталось "-0"
double fmt (double a, double eps) { return (abs(a) < eps ? 0. : a); }

int main() {
 const double eps = 1e-12; //погрешность 
 double a,b,c,d,x1,x2;
 cout << "Hello, I can solve Quadratic equation a * x ^ 2 + b * x + c = 0" << endl;
 do {
  do {
   cout << "Type real or integer a, b, c (space delimited): ";
   cin >> a >> b >> c;
   if (cin.good()) break;
   cin.clear();
   cin.ignore(INT_MAX, '\n');
  } while (1);
  cout.precision(3); //сколько знаков в дробной части выводим
  if (equal(a,0.,eps)) { 
   if (equal(b, 0., eps)) {
    if (equal(c, 0., eps)) cout << "Identity 0 = 0";
    else cout << "An equation like C = 0 is inconsistent";
   }
   else cout << "X=" << fmt(-c / b, eps) << ", linear equation";
  }
  else {
   d = pow(b, 2) - 4 * a * c;
   if (d < 0) {
    x1 = -b / (2 * a);
    x2 = sqrt(abs(d)) / (2 * a);
    cout << "X1=" << fmt(x1, eps) << "+" << fmt(x2, eps) << "i, " <<
            "X2=" << fmt(x1, eps) << "-" << fmt(x2, eps) << "i, " << 
            " complex roots";
   }
   else if (equal(d, 0., eps)) {
    cout << "X=" << fmt(-b / (2 * a), eps) << ", single root";
   }
   else {
    x1 = (-b + sqrt(d)) / (2 * a);
    x2 = (-b - sqrt(d)) / (2 * a);
    cout << "X1=" << fmt(x1, eps) << ", X2=" << fmt(x2, eps);
   }
  }
  char action = '0';
  do {
   cout << endl << endl << 
    "Press 1 and Enter to solve other equation, 0 and Enter to exit: ";
   cin >> action;
   if (cin.good()) break;
   cin.clear();
   cin.ignore(INT_MAX, '\n');
  } while (1);
  if (action == '0') break;
 } while (1);
 return 0;
}

16. Переписать в std::vector построчно элементы статического и динамического двумерного массива.

Для статического можно, например, так:

 const int n = 3, m = 4;
 int b[n][m] = {
 {1,2,0,3},
 {4,5,6,9},
 {7,9,8,1}
 };
 int* start = &b[0][0];
 vector <int> v(start, start + (n * m));
С динамическим придётся ещё пробежаться по строкам. Для простоты контроль выделения памяти не делается.

 const int n = 3, m = 4;
 int **b = new int * [n];
 for (size_t i = 0; i < n; i++) {
  b[i] = new int [m];
  for (size_t j = 0; j < m; j++) b[i][j] = i + j;
 }
 vector <int> v;
 for (size_t i = 0; i < n; i++) {
  int* start = &b[i][0];
  v.insert(v.end(), start, start + m);
 }

17. На вход прораммы подаётся n целых чисел. Сформировать контейнер с различной длиной строк по следующему правилу: в первой строке расположить числа, оканчивающиеся на 0, во второй – на 1, в третьей на 2, и т.д. Одинаковые значения в контейнер не добавлять.

#include <iostream>
#include <vector>
#include <set>
using namespace std;

int main() {
 const size_t n = 100;
 vector <set<int>> a(10);
 
 cout << "Our data: ";
 int val;
 for (size_t i = 0; i < n; i++) {
  val = rand() % 100;
  a.at(val % 10).insert(val);
  cout << val << ' ';
 }
 set<int>::iterator it;
 for (size_t i = 0; i < 10; i++) {
  cout << endl << "String " << i << ": ";
  for (it = a.at(i).begin(); it != a.at(i).end(); ++it) cout << *it << ' ';
 }

 return 0;
}

30.05.2021, 18:54 [1295 просмотров]


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

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