Ещё 15 задач про числа за май 2018-го
Что ж, вот закончатся когда-нибудь мокрый снег и дождь, возможно, даже настанет лето, тогда и перестанем решать задачи. А пока что - очередная подборка алгоритмических задач на C++, предыдущая - в этой заметке.
Все задачи выполнялись как консольные приложения Visual Studio 2015, для быстрого поиска на странице статьи нужного слова в любом современном браузере можно использовать комбинацию клавиш Ctrl+F.
1. Серик и Берик собрали все яблоки в саду. Сезон подходит к концу и в саду осталось очень мало яблок. Вместе они собрали всего N корзинок с яблоками. По этой причине ребята решают поделить все собранные яблоки. Однако Серику не понравилось предложение Берика поделить всё количество яблок поровну. В этом случае кому-то может достаться больший вес яблок, так как у каждого яблока разный вес. Серик предложил поделить яблоки в каждой корзинке с помощью монетки.
Берик и Серик выложили яблоки из каждой корзинки перед собой в ряд. Таким образом, получилось N рядов с корзинками. Для каждого ряда ребята поочередно бросают монетку: если монетка падает решкой, то бросивший её берёт первое яблоко в ряду. Если выпадает орёл, то берут последнее яблоко в ряду.
Формат входных данных: первая строка содержит целое число N, количество корзинок с яблоками. Для каждой из N корзинок пишется две последующие строки: первая строка M – количество яблок в корзинке, вторая строка - веса Vi каждого яблока в корзинке.
Ограничения: 1 ≤ N ≤ 500 1 ≤ M ≤ 2000 0 ≤ Vi ≤ 999, 1 ≤ i ≤ M
Для каждой корзинки вывести, какой общий вес Берик и Серик получат из неё, при условии, что Серик бросает монетку первым.
//Visual Studio 2015 #include <iostream> #include <fstream> #include <vector> #include <cstdlib> #include <ctime> using namespace std; void error(char *message, int errorcode) { //Сообщение о статусе программы и выход cout << endl << message; cout << endl << "Press Enter to EXIT"; system("pause>nul"); exit(errorcode); } int main() { ifstream f("input.txt"); if (!f) error("Can't open file data.txt", 1); //Не удалось открыть файл int n; f >> n; if (f.fail() || n<2 || n>500) error("Bad N value!", 2); //Неверное N vector < vector <int> > basket(n); int summa = 0; //Всего яблок for (int i = 0; i < n; i++) { int m; f >> m; if (f.fail() || m<2 || m>2000) error("Bad M value!", 3); //Неверное M for (int j=0; j<m; j++) { double weight; f >> weight; if (f.fail() || weight<0 || weight>999) error("Bad weight value!", 4); //Неверный вес basket[i].push_back (weight); } summa += m; } f.close(); srand(time(0)); vector <int> berik(n,0), serik(n,0); int cnt = 0; while (cnt < summa) { //пока всё не разобрали for (int i = 0; i < n; i++) { int m = basket[i].size(); if (m) { //кинул Серик int c = rand()%2; int index = c ? 0 : m - 1; serik[i] += basket[i][index]; cnt++; basket[i].erase (basket[i].begin() + index); m = basket[i].size(); if (m) { //кинул Берик int c = rand() % 2; int index = c ? 0 : m - 1; berik[i] += basket[i][index]; cnt++; basket[i].erase(basket[i].begin() + index); } else { //кинули Берика } } } } for (int i = 0; i < n; i++) { cout << "basket " << (i+1) << ", Berik = " << berik[i] << ", Serik = " << serik[i] << endl; } error("OK",0); }
Файл input.txt был таким:
4 6 500 300 250 450 900 300 5 234 965 123 432 234 4 100 200 300 400 5 250 650 345 654 321
2. Создать массив целых чисел и заполнить его случайными значениями.
Размерность массива = 100 и диапазон значений чисел - от -100 до 100 включительно.
Найти непрерывный участок, на котором сумма положительных элементов максимальна.
При этом 0 считается положительным числом, а длина последовательности больше 1.
Если не использовать стандартных векторов и алгоритмов, то самое простое так:
//Visual Studio 2015 #include <iostream> #include <cstdlib> #include <ctime> using namespace std; int main() { const int n = 100; int a[n]; srand(time(0)); //чтобы числа были разными каждый раз! for (int i=0; i<n; i++) { a[i] = -100 + rand()%201; cout << a[i] << " "; } int sum = 0; //текущая сумма чисел >=0 int maxsum = 0; //максимальная из таких сумм int len = 0; //длина цепочки int maxlen = 0; //максимальная из длин цепочек int index = -1; //начало самой длинной цепочки for (int i = 0; i < n; i++) { if (a[i] >= 0) { sum += a[i]; len++; if (len > 1) { if (sum > maxsum) { index = i + 1 - len; maxsum = sum; maxlen = len; } } } else len = sum = 0; } if (index == -1) { cout << "Chain not found!"; } else { cout << endl << "Length = " << maxlen << ", Summa = " << maxsum << ", Index = " << index; cout << endl << "Items = "; for (int i = index; i < index+ maxlen; i++) cout << a[i] << " "; } cin.get(); return 0; }
3. Задана матрица А с 2 строками и 70 столбцами. 1-й элемент каждого столбца представляют собой абсциссу, а 2-й — ординату одной из 70 точек на плоскости. Определить среднее значение расстояний от начала координат тех точек, которые лежат в левой полуплоскости.
//Visual Studio 2015 #include <iostream> #include <cmath> using namespace std; int main() { const int n = 70; double a[2][n]; for (int j = 0; j < n; j++) { for (int i = 0; i < 2; i++) { a[i][j] = -100 + rand()%201; //диапазон значений [-100;100] } cout << "Point " << (j+1) << "=(" << a[0][j] << "," << a[1][j] <<") "; } double average = 0; int count = 0; for (int j = 0; j < n; j++) { if (a[0][j]<0) { //x<0, левая полуплоскость average += sqrt(pow(a[0][j],2)+pow(a[1][j],2)); //прибавить очередное расстояние count++; } } if (count > 0 ) { average /= count; //найти среднее cout << endl << "Average = " << average; } else cout << endl << "Not found!"; cin.get(); return 0; }
4. Задача о раскраске графа. Граф представлен структурой Вирта. Вот 3 работающих в консоли Visual Studio 2015 программки, не очень оптимизированы, зато с комментариями.
4.1. Обход в глубину
//Visual Studio 2015 //Последовательная раскраска вершин графа при помощи //обхода графа в глубину. //Граф представлен структурой Вирта. #include <iostream> #include <windows.h> using namespace std; #define TRUE 1 #define FALSE 0 typedef int Boolean; typedef struct L *Lref; // Тип: указатель на заголовочный узел. typedef struct T *Tref; // Тип: указатель на дуговой узел. //Описание типа заголовочного узла. typedef struct L { int Key; //Имя заголовочного узла. int Color; //Цвет раскраски. int Count; //Количество предшественников. Boolean Flag; //Флаг посещения узла при обходе. Tref Trail; //Указатель на список смежности. Lref Next; //Указатель на следующий узел в списке заголовочных узлов. }; //Описание типа дугового узла. typedef struct T { Lref Id; Tref Next; }; class Spisok { private: Lref Head; //Указатель на голову списка заголовочных узлов. Lref Tail; //Указатель на фиктивный элемент // в конце списка заголовочных узлов. int MSet[256]; //Вспомогательное множество, содер- //жащее 0,1,2...,n. void SearchGraph(int, Lref *); public: Spisok() {//Инициализация списка заголовочных узлов. Head = Tail = new (L); } Lref GetHead() { return Head; } Lref GetTail() { return Tail; } void MakeGraph(); void PrintGraph(); void Color(Lref, int); void Postr(int); }; void Spisok::Postr(int n) //Построение вспомогательного множества MSet. { for (int i = 0; i<256; i++) MSet[i] = (i <= n) ? 1 : 0; } void Spisok::SearchGraph(int w, Lref *h) //Функция возвращает указатель на заголовочный узел //с ключом w в графе, заданном структурой Вирта с указателем Head. { *h = Head; (*Tail).Key = w; while ((**h).Key != w) *h = (**h).Next; if (*h == Tail) //В списке заголовочных узлов нет узла с ключом w. //Поместим его в конец списка Head. { Tail = new (L); (**h).Count = 0; (**h).Trail = NULL; (**h).Next = Tail; } } void Spisok::MakeGraph() //Функция возвращает указатель Head на структуру //Вирта, соответствующую ориентированному графу. { int x, y; Lref p, q; //Рабочие указатели. Tref t, r; //Рабочие указатели. Boolean Res; //Флаг наличия дуги. cout << "Вводите начальную вершину дуги: "; cin >> x; while (x != 0) { cout << "Вводите конечную вершину дуги: "; cin >> y; //Определим, существует ли в графе дуга (x,y)? SearchGraph(x, &p); SearchGraph(y, &q); r = (*p).Trail; Res = FALSE; while ((r != NULL) && (!Res)) if ((*r).Id == q) Res = TRUE; else r = (*r).Next; if (!Res) //Если дуга отсутствует, то поместим её в граф. { t = new (T); (*t).Id = q; (*t).Next = (*p).Trail; (*p).Trail = t; (*q).Count++; } cout << "Вводите начальную вершину дуги (0 - выход): "; cin >> x; } } void Spisok::PrintGraph() //Вывод структуры Вирта, заданной указателем //Head и соответствующей ориентированному графу. { Lref p; //Рабочий указатель. Tref q; //Рабочий указатель. p = Head; while (p != Tail) { cout << (*p).Key << "("; q = (*p).Trail; while (q != NULL) { cout << (*(*q).Id).Key; q = (*q).Next; } cout << ")"; p = (*p).Next; cout << " "; } } void Spisok::Color(Lref r, int n) //Последовательная раскраска графа при помощи //рекурсивного обхода графа в глубину. //r - указатель на структуру Вирта. //MSet - глобальное множество. //n - количество вершин в графе. { Tref t, t1; int i; //Параметр цикла. Boolean Fl; t = r->Trail; r->Flag = FALSE; //Сейчас мы находимся в вершине r->Key. //Исключим цвета всех вершин, смежных вершине //r->Key, из множества MSet. t1 = t; while (t1 != NULL) { MSet[t1->Id->Color] = 0; t1 = t1->Next; } //Выбор цвета вершины: это "первый" элемент множества MSet. Fl = TRUE; i = 1; while (Fl) if (MSet[i]) Fl = FALSE; else i++; r->Color = i; //Цвет присвоен! cout << "(" << r->Key << "," << r->Color << ") "; //Восстановление вспомогательного множества MSet. for (i = 0; i<256; MSet[i++] = 0); for (i = 0; i <= n; MSet[i++] = 1); // ------------- while (t != NULL) { if (t->Id->Flag) Color(t->Id, n); t = t->Next; } } int main() { SetConsoleCP(1251); SetConsoleOutputCP(1251); //Если нет русских букв при вводе, поставьте шрифт Lucida Console в свойствах окна консоли Spisok A; Lref t; //Рабочий указатель для перемещения // по списку заголовочных звеньев. int n = 0; //Количество вершин в графе. //Построение графа и вывод его структуры Вирта. A.MakeGraph(); A.PrintGraph(); cout << endl; //Раскраска с помощью рекурсивного обхода графа в глубину. //Инициализация. t = A.GetHead(); //Установлен рабочий указатель. while (t != A.GetTail()) { t->Flag = TRUE; t->Color = 0; n++; t = (*t).Next; } // ------------------------------------ //Построение вспомогательного множества MSet. A.Postr(n); cout << "Результат раскраски: "; A.Color(A.GetHead(), n); system("pause"); return 0; }
4.2. Обход в ширину
//Visual Studio 2015 // Последовательная раскраска графа при помощи //обхода графа в ширину. //Граф представлен структурой Вирта. #include <iostream> #include <windows.h> using namespace std; #define TRUE 1 #define FALSE 0 typedef int Boolean; typedef struct Leader *Lref; // Тип: указатель на заголовочный узел. typedef struct Trailer *Tref; // Тип: указатель на дуговой узел. //Описание типа заголовочного узла. typedef struct Leader { int Key; //Имя заголовочного узла. int Count; //Количество предшественников. int Color; //Цвет раскраски. Boolean Flag; //Флаг посещения узла при обходе. Tref Trail; //Указатель на список смежности. Lref Next; //Указатель на следующий узел в списке заголовочных узлов. }; //Описание типа дугового узла. typedef struct Trailer { Lref Id; Tref Next; }; //Описание типа узла очереди. typedef Lref TipElement; //Указатель на звено заголовочного списка. typedef struct Zveno *svqz; typedef struct Zveno { TipElement Element; //Указатель на список смежности. svqz Sled; }; class Spisok { private: Lref Head; //Указатель на голову списка заголовочных узлов. Lref Tail; //Указатель на фиктивный элемент // в конце списка заголовочных узлов. int MSet[256]; //Вспомогательное множество, содер- //жащее 0,1,2...,n. void Udalenie_A(svqz *, svqz *, TipElement *); void Dobavlenie(svqz *, svqz *, TipElement); void SearchGraph(int, Lref *); public: Spisok() {//Инициализация списка заголовочных узлов. Head = Tail = new (Leader); } Lref GetHead() { return Head; } Lref GetTail() { return Tail; } void MakeGraph(); void PrintGraph(); void Color(Lref, int); void Postr(int); }; void Spisok::Postr(int n) //Построение вспомогательного множества MSet. { for (int i = 0; i<256; i++) MSet[i] = (i <= n) ? 1 : 0; } void Spisok::SearchGraph(int w, Lref *h) //Функция возвращает указатель на заголовочный узел //с ключом w в графе, заданном структурой Вирта с указателем Head. { *h = Head; (*Tail).Key = w; while ((**h).Key != w) *h = (**h).Next; if (*h == Tail) //В списке заголовочных узлов нет узла с ключом w. //Поместим его в конец списка Head. { Tail = new (Leader); (**h).Count = 0; (**h).Trail = NULL; (**h).Next = Tail; } } void Spisok::MakeGraph() //Функция возвращает указатель Head на структуру //Вирта, соответствующую ориентированному графу. { int x, y; Lref p, q; //Рабочие указатели. Tref t, r; //Рабочие указатели. Boolean Res; //Флаг наличия дуги. cout << "Вводите начальную вершину дуги: "; cin >> x; while (x != 0) { cout << "Вводите конечную вершину дуги: "; cin >> y; //Определим, существует ли в графе дуга (x,y)? SearchGraph(x, &p); SearchGraph(y, &q); r = (*p).Trail; Res = FALSE; while ((r != NULL) && (!Res)) if ((*r).Id == q) Res = TRUE; else r = (*r).Next; if (!Res) //Если дуга отсутствует, то поместим её в граф. { t = new (Trailer); (*t).Id = q; (*t).Next = (*p).Trail; (*p).Trail = t; (*q).Count++; } cout << "Вводите начальную вершину дуги: "; cin >> x; } } void Spisok::PrintGraph() //Вывод структуры Вирта, заданной указателем //Head и соответствующей ориентированному графу. { Lref p; //Рабочий указатель. Tref q; //Рабочий указатель. p = Head; while (p != Tail) { cout << (*p).Key << "("; q = (*p).Trail; while (q != NULL) { cout << (*(*q).Id).Key; q = (*q).Next; } cout << ")"; p = (*p).Next; cout << " "; } } void Spisok::Dobavlenie(svqz *L, svqz *R, TipElement elem) //Добавление элемента elem в очередь, заданную указателями L и R. { svqz K = new (Zveno); K->Element = elem; K->Sled = NULL; if (*L == NULL) { (*L) = K; (*R) = K; } else { (*R)->Sled = K; (*R) = K; } } void Spisok::Udalenie_A(svqz *L, svqz *R, TipElement *A) //Удаление элемента из очереди, заданной указателями L и R и //помещение удаленного элемента в переменную A. { svqz q; if ((*L) != NULL) if ((*L)->Sled != NULL) { (*A) = (*L)->Element; q = (*L); (*L) = (*L)->Sled; delete q; } else { (*A) = (*L)->Element; delete *L; (*L) = (*R) = NULL; } } void Spisok::Color(Lref H, int n) //Последовательная раскраска графа при помощи обхода графа //в ширину, начиная с вершины, заданной указателем H //(нерекурсивный обход). { svqz L; // Указатель на начало очереди. svqz R; // Указатель на конец очереди. Lref p; // Рабочий указатель. Tref t; // Рабочий указатель. Tref t1; int i; // Параметр цикла. Boolean Fl; L = R = NULL; // Создание пустой очереди. Dobavlenie(&L, &R, H); H->Flag = FALSE; while (L != NULL) { //Пока очередь не пуста... Udalenie_A(&L, &R, &p); t = p->Trail; //Сейчас мы находимся в вершине r->Key. //Исключим цвета всех вершин, смежных вершине //r->Key, из множества MSet. t1 = t; while (t1 != NULL) { MSet[t1->Id->Color] = 0; t1 = t1->Next; } //Выбор цвета вершины - "первого" элемента множества MSet. Fl = TRUE; i = 1; while (Fl) if (MSet[i]) Fl = FALSE; else i++; p->Color = i; //Цвет присвоен! cout << "(" << p->Key << "," << p->Color << ") "; //Восстановление вспомогательного множества MSet. for (i = 0; i<256; MSet[i++] = 0); for (i = 0; i <= n; MSet[i++] = 1); while (t != NULL) { if (t->Id->Flag) { Dobavlenie(&L, &R, t->Id); t->Id->Flag = FALSE; } t = t->Next; } } } int main() { SetConsoleCP(1251); SetConsoleOutputCP(1251); //Если нет русских букв при вводе, поставьте шрифт Lucida Console в свойствах окна консоли Spisok A; Lref t; //Рабочий указатель для перемещения // по списку заголовочных звеньев. int n = 0; //Количество вершин в графе. //Построение графа и вывод его структуры Вирта. A.MakeGraph(); A.PrintGraph(); cout << endl; //Раскраска с помощью рекурсивного обхода графа в ширину. //Инициализация. t = A.GetHead(); //Установлен рабочий указатель. while (t != A.GetTail()) { t->Flag = TRUE; t->Color = 0; n++; t = (*t).Next; } // ------------------------------------ //Построение вспомогательного множества MSet. A.Postr(n); cout << "Результат раскраски: "; A.Color(A.GetHead(), n); system("pause"); return 0; }
4.3. Раскраска, если граф представлен списками смежности
//Visual Studio 2015 //Последовательная раскраска графа, представленного с помощью //модифицированных списков смежности. #include <iostream> #include <windows.h> using namespace std; #define TRUE 1 #define FALSE 0 #define XRY 8 //Количество вершин графа. typedef int Boolean; typedef struct zveno *svqz; typedef struct zveno { int Key; // Вершина графа. svqz Up; // Указатель на смежную вершину. svqz Sled;// Указатель на следующую смежную вершину. }; class Spisok { private: svqz Beg[XRY + 1]; //Массив указателей на вершины. void Add_Ver(int); int Find(int, int, svqz *); void Add_duga(int, int); void Make(int, int); void Delinenok(int, int); void Del_Duga(int, int); void Del_Ver(int); int Find_Color(int, int, svqz *); public: Spisok(); void Init_Graph(); void Make_Graph(); void Print_Graph(); void Color(); void Print_Color(); }; Spisok::Spisok() { for (int i = 0; i <= XRY; Beg[i++] = NULL); } void Spisok::Add_Ver(int x) //Функция создания вершины x. { svqz Ukaz = new (zveno); Ukaz->Sled = NULL; Beg[x] = Ukaz; } void Spisok::Init_Graph() //Функция инициализации модифицированных списков смежности. { for (int i = 1; i <= XRY; i++) Add_Ver(i); } int Spisok::Find(int x, int y, svqz *UkZv) //Функция проверки смежности вершин y и x. Функция возвращает //TRUE, если вершина x смежна с вершиной y. Указатель *UkZv, //возвращает указатель на место y в списке смежности x. Если //вершина x не смежна с вершиной y, то UkZv есть NULL. { svqz Ukaz; Ukaz = Beg[x]->Sled; while (Ukaz != NULL && Ukaz->Key != y) Ukaz = Ukaz->Sled; *UkZv = Ukaz; return (Ukaz != NULL); } void Spisok::Add_duga(int x, int y) //Функция создания дуги (x,y). { svqz Ukaz = new (zveno); Ukaz->Sled = Beg[x]->Sled; Ukaz->Key = y; Beg[x]->Sled = Ukaz; } void Spisok::Make(int x, int y) //Функция создания ребра {x,y}. { svqz Ukaz; if (!Find(x, y, &Ukaz)) { Add_duga(x, y); if (x != y) Add_duga(y, x); Beg[x]->Sled->Up = Beg[y]; Beg[y]->Sled->Up = Beg[x]; } } void Spisok::Make_Graph() //Функция построения модифицированных списков смежности. { int f; for (int i = 1; i <= XRY; i++) { cout << "Введите вершины, смежные с " << i << "-й вершиной: "; cin >> f; while (f != 0) { Make(i, f); cout << " "; cin >> f; } cout << endl; } } void Spisok::Delinenok(int x, int y) //Функция удаления дуги (x,y). { svqz Ukaz; svqz Ukazlenok; Ukazlenok = Beg[x]; Ukaz = Beg[x]->Sled; while (Ukaz != NULL && Ukaz->Key != y) { Ukazlenok = Ukaz; Ukaz = Ukaz->Sled; } if (Ukaz != NULL) { Ukazlenok->Sled = Ukaz->Sled; delete Ukaz; } } void Spisok::Del_Duga(int x, int y) //Функция удаления ребра {x,y}. { Delinenok(x, y); Delinenok(y, x); } void Spisok::Del_Ver(int x) //Функция удаления вершины x. { svqz Ukaz; svqz Ukazlenok; for (int i = 1; i <= XRY; i++) Delinenok(i, x); Ukaz = Beg[x]; Beg[x] = NULL; while (Ukaz != NULL) { Ukazlenok = Ukaz->Sled; delete Ukaz; Ukaz = Ukazlenok; } } void Spisok::Print_Graph() //Функция вывода содеpжимого модифицированных //списков смежности. { svqz UkZv; for (int i = 1; i <= XRY; i++) { if (Beg[i] != NULL) { UkZv = Beg[i]->Sled; cout << i << " - "; while (UkZv != NULL) { cout << " " << UkZv->Key; UkZv = UkZv->Sled; } } cout << endl; } } int Spisok::Find_Color(int x, int c, svqz *UkZv) //Функция выявления возможности раскраски вершины x цветом c. //Функция возвращает TRUE, если вершину x можно раскрасить. //Указатель *UkZv, возвращает указатель на вершину, смежную с x //и раскрашенную цветом c. Если вершину x можно раскрасить, то //*UkZv есть NULL. { int i = 1; while (!(Find(x, i, &(*UkZv)) && Beg[i]->Key == c) && i != x) i++; return (i == x); } void Spisok::Color() //Функция последовательной раскраски графа, заданного //модифицированными списками смежности Beg. { int i = 1; int c = 1; svqz UkZv; while (Beg[i] == NULL && i <= XRY) i++; if (i != XRY) { Beg[i]->Key = c; i++; while (i <= XRY) if (Beg[i] != NULL) { c = 1; while (!Find_Color(i, c, &UkZv)) c++; Beg[i]->Key = c; i++; } else i++; } else cout << "Граф отсутствует!"; } void Spisok::Print_Color() //Функция вывода раскраски графа, заданного //модифицированными списками смежности Beg. { for (int i = 1; i <= XRY; i++) if (Beg[i] != NULL) cout << " Color " << i << " - " << Beg[i]->Key << endl; } int main() { SetConsoleCP(1251); SetConsoleOutputCP(1251); //Если нет русских букв при вводе, поставьте шрифт Lucida Console в свойствах окна консоли Spisok A; //Инициализация графа. A.Init_Graph(); //Построение графа. A.Make_Graph(); //Вывод графа. A.Print_Graph(); //Последовательная раскраска графа, представленного //модифицированными списками смежности. A.Color(); A.Print_Color(); system("pause"); return 0; }
5. Даны целые положительные числа M, N и набор из M целых значений. Сформировать матрицу размера M х N, у которой в каждом столбце содержатся все числа из исходного набора, записанные в том же порядке.
//Visual Studio 2015 #include <iostream> using namespace std; int main() { const int m = 5, n = 6; //размерности int v[m] = {1,2,3,4,5}; //набор int **a; //матрица a = new int * [m]; for (int i = 0; i<m; i++) { a[i] = new int[n]; for (int j = 0; j<n; j++) { a[i][j] = v[i]; cout << a[i][j] << " "; } cout << endl; } cin.get(); return 0; }
6. Вычислить сумму n первых членов ряда
интересный ряд
Как обычно, стараемся обойтись без лишних повторяющихся расчётов, накапливая части формулы в промежуточных переменных.
//Visual Studio 2015 #include <iostream> using namespace std; int main() { int n = 10; //или ввести число double x = 0.1; //x тоже должно быть задано double sum = 0, z = 1, pr = 1; for (int i=1; i<=2*n-1; i+=2) { sum += z * pr * x / i; x *= x*x; pr *= (double)i / (i + 1); z = -z; } cout.precision(15); cout << sum; cin.get(); return 0; }
7. Два двузначных числа, записанных одно за другим , образуют четырёхзначное число, которое без остатка делится на их произведение. Найти все пары таких чисел.
//Visual Studio 2015 #include <iostream> using namespace std; int main() { for (int a = 10; a < 100; a++) { for (int b = 10; b < 100; b++) { int c = a*100+b; if (c%(a*b)==0) cout << endl << a << " " << b << " " << c << " " << a*b << " " << c/(a*b); } } cin.get(); return 0; }
8. Написать функцию для возведения целого значения x в натуральную степень y с временной сложностью алгоритма O(Log y)
//Visual Studio 2015 #include <iostream> using namespace std; int power(int x, unsigned int y) { int res = 1; while (y > 0) { if (y & 1) res = res * x; y = y >> 1; // y/=2; x = x * x; } return res; } int main() { cout << power(3,5); cin.get(); return 0; }
9. Представить заданную дробь в виде Египетской дроби.
Алгоритм не самый сильный и может переполнить стек для некоторых дробей.
//Visual Studio 2015 #include <iostream> #include <string> using namespace std; string printEgyptian (int ch, int zn) { if (ch == 0 || zn == 0) return ""; if (zn%ch == 0) return string("1/") + to_string(zn/ch); if (ch%zn == 0) return to_string(ch) + string("/") + to_string(zn); if (ch > zn) return to_string(ch) + string("/") + to_string(zn) + string("+") + printEgyptian(ch%zn, zn); int n = zn / ch + 1; return string("1/") + to_string(n) + string("+") + printEgyptian(ch*n - zn, zn*n); } int main() { int ch = 7, zn = 15; cout << ch << "/" << zn << "=" << printEgyptian(ch, zn); cin.get(); return 0; }
10. Найти угол между часовой и минутной стрелками на 12-часовом циферблате.
Вот здесь мы искали время до момента, когда стрелки окажутся на одной линии, попробуем просто определить угол между стрелками.
Угол считается "без знака" и принимает значения от 0 до 180 градусов.
//Visual Studio 2015 #include <iostream> #include <algorithm> #include <climits> using namespace std; int calcAngle(double h, double m) { if (h <0 || m < 0 || h >12 || m > 60) return INT_MAX; if (h == 12) h = 0; if (m == 60) m = 0; int hour_angle = 0.5 * (h * 60 + m); int minute_angle = 6 * m; int angle = abs(hour_angle - minute_angle); return min(360 - angle, angle); } int main() { cout << "For time 9:60=" << calcAngle(9, 60) << endl; cout << "For time 11:36=" << calcAngle(11, 36) << endl; cout << "For time 6:01=" << calcAngle(6, 1) << endl; cin.get(); return 0; }
Или ещё проще:
#include <iostream> #include <cmath> #include <algorithm> using namespace std; double calcAngle(unsigned h, unsigned m) { h += m / 60; h %= 12; m %= 60; double hour_angle = 0.5 * (h * 60 + m); double minute_angle = 6 * m; double angle = abs(hour_angle - minute_angle); angle = min (360 - angle, angle); return angle; } int main() { cout << calcAngle(9,120); //30 cout << endl << calcAngle(15, 30); //75 cin.get(); return 0; }
11. Найти n-ое по порядку число Каталана.
Используем подход без рекурсии на основе вычисления биномиальных коэффициентов, его временная сложность будет порядка O(n). Нумерация чисел, по определению, предполагается с нуля.
//Visual Studio 2015 #include <iostream> using namespace std; unsigned long int binomialCoeff (unsigned int n, unsigned int k) { unsigned long int res = 1; if (k > n - k) k = n - k; // C(n, k) = C(n, n-k) for (int i = 0; i < k; ++i) { // [n*(n-1)*---*(n-k+1)] / [k*(k-1)*---*1] res *= (n - i); res /= (i + 1); } return res; } unsigned long int catalan(unsigned int n) { unsigned long int c = binomialCoeff(2 * n, n); return c / (n + 1); } int main() { cout << catalan(10); cin.get(); return 0; }
12. Русское крестьянское умножение :)
Так у них, но не у нас, называют народный метод умножения, основанный на умножении и делении на два.
//Visual Studio 2015 #include <iostream> using namespace std; unsigned int russianPeasantMult (unsigned int a, unsigned int b) { int res = 0; while (b > 0) { if (b & 1) res = res + a; a = a << 1; b = b >> 1; } return res; } int main() { cout << "30*12=" << russianPeasantMult(30,12) << endl; cout << "198*77=" << russianPeasantMult(198, 77) << endl; cin.get(); return 0; }
13. Определить, пересекаются ли 2 отрезка на плоскости, заданные целочисленными координатами начала и конца.
Несмотря на простоту постановки, задача не столь уж тривиальна, если учесть все случаи. Поэтому и ограничимся целочисленными координатами концов отрезков.
//Visual Studio 2015 #include <iostream> #include <algorithm> using namespace std; struct Point { int x; int y; }; //точка bool onSegment(Point p, Point q, Point r) { // лежит ли точка q на отрезке 'pr' if (q.x <= max(p.x, r.x) && q.x >= min(p.x, r.x) && q.y <= max(p.y, r.y) && q.y >= min(p.y, r.y)) return true; return false; } int orientation(Point p, Point q, Point r) { //ориентация триплета (p,q,r) //0 - на одной прямой, 1 - по часовой, 2 - против часовой int val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y); if (val == 0) return 0; return (val > 0) ? 1 : 2; } bool doIntersect(Point p1, Point q1, Point p2, Point q2) { //Пересечение отрезков p1-q1 и p2-q2 int o1 = orientation(p1, q1, p2); int o2 = orientation(p1, q1, q2); int o3 = orientation(p2, q2, p1); int o4 = orientation(p2, q2, q1); if (o1 != o2 && o3 != o4) return true; //p1, q1 и p2 на одной прямой и p2 на отрезке p1q1 if (o1 == 0 && onSegment(p1, p2, q1)) return true; // p1, q1 и q2 на одной прямой и q2 на отрезке p1q1 if (o2 == 0 && onSegment(p1, q2, q1)) return true; // p2, q2 и p1 на одной прямой и p1 на отрезке p2q2 if (o3 == 0 && onSegment(p2, p1, q2)) return true; // p2, q2 и q1 на одной прямой и q1 на отрезке p2q2 if (o4 == 0 && onSegment(p2, q1, q2)) return true; return false; } int main() { struct Point p1 = { 10,0 }, q1 = { 0,10 }; struct Point p2 = { 1,1 }, q2 = { 10,10 }; if (doIntersect(p1, q1, p2, q2)) cout << "Yes"; else cout << "No"; cin.get(); return 0; }
14. На вход подпрограммы (потока) поступают целые числа. Организовать выбор случайного числа с временной сложностью алгоритма O(1).
Когда-то делал такое на Perl, вот на C++. Но чудес от такого алгоритма не ждите, будут повторы :)
//Visual Studio 2015 #include <iostream> #include <cstdlib> #include <ctime> using namespace std; int selectRandom (int x) { static int res; static int count = 0; //сколько было чисел count++; if (count == 1) res = x; //первое число всегда возвращаем else { //иначе возвращаем число с вероятностью 1/count int i = rand() % count; if (i == count - 1) res = x; } return res; } int main() { int stream[] = { 11, 22, 33, 44, 55, 66, 77, 88, 99 }; int n = sizeof(stream) / sizeof(stream[0]); srand(time(NULL)); for (int i = 0; i < n; i++) { cout << selectRandom(stream[i]) << endl; } cin.get(); return 0; }
15. Проверить, является ли заданное натуральное число счастливым.
У задачи есть несколько формулировок.
Во-первых, можно считать в смысле последовательности A000959, в русской Вики это описано как очередное "Счастливое число", хотя на самом деле "удачливое" (Lucky), в отличие от "Happy" из этой заметки.
Во-вторых, если мы будем на n-ом шаге вычёркивать каждое (n+1)-ое число, а не число с номером, полученным из n-ого из оставшихся чисел, мы придём несколько к другой последовательности, A000960, связанной с задачей Иосифа Флавия в одной из её формулировок. На этом варианте и остановимся, для надёжности напечатав достаточно длинную цепочку "lucky numbers".
Также, для разнообразия, используем итерации вместо рекурсии (что, вообще говоря, можно сделать всегда, и не рисковать переполнением стека).
//Visual Studio 2015 #include <iostream> using namespace std; bool isLucky (int n) { for (int i = 2; i <= n; i++) { if (n%i == 0) return false; n -= n / i; } return true; } int main() { for (int i = 1; i <= 3000; i++) { if (isLucky(i)) cout << i << " "; } cin.get(); return 0; }
17.05.2018, 13:37 [2880 просмотров]