Ещё 16 не пригодившихся задач за апрель 2018
В продолжение предыдущей подборки из 14 задач, в апреле же 30 дней :)
Все задачи проверены в консоли Visual Studio 2015 и написаны на C++. По-прежнему материал серии не упорядочен тематически, ну, потом когда-нибудь :)
Для быстрого поиска на странице нужного слова нажмите в браузере комбинацию клавиш Ctrl+F
.
1. Создать структуру колоды карт, состоящую из двух полей - переменных перечислимого типа "масть" и "старшинство". Сформировать случайную перетасовку карт для трех игроков.
#include <iostream> #include <vector> #include <algorithm> #include <string> #include <ctime> using namespace std; enum CardSuit { CLUBS, DIAMONDS, HEARTS, SPADES }; enum CardRank { SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE }; #define stringify( name ) # name const char* CardSuitNames[] = { stringify(CLUBS), stringify(DIAMONDS), stringify(HEARTS), stringify(SPADES) }; const char* CardRankNames[] = { stringify(SIX), stringify(SEVEN), stringify(EIGHT), stringify(NINE), stringify(TEN), stringify(JACK), stringify(QUEEN), stringify(KING), stringify(ACE) }; struct Card { CardSuit suit; CardRank rank; }; void print(Card c) { cout << CardSuitNames[c.suit] << " " << CardRankNames[c.rank]; } void printDeck(vector <Card> &deck) { for (int i = 0; i<deck.size(); i++) { cout << endl << (i + 1) << " "; print(deck[i]); } } int main() { vector <Card> deck; Card c; for (int i = 0; i<36; i++) { c.suit = static_cast<CardSuit>(i % 4); c.rank = static_cast<CardRank>(i % 9); deck.push_back(c); } cout << endl << endl << "Generated deck" << endl; printDeck(deck); sort(deck.begin(), deck.end(), [&](const Card &a, const Card &b) { return a.suit < b.suit || a.suit == b.suit && a.rank < b.rank; } ); cout << endl << endl << "Sorted deck" << endl; printDeck(deck); const int n = 3; vector <Card> players[n]; srand(time(0)); for (int i = 0; i < n; i++) { players[i] = deck; random_shuffle(players[i].begin(), players[i].end()); cout << endl << endl << "Player " << (i + 1) << endl; printDeck(players[i]); } cin.get(); return 0; }
Пример более "индусского" варианта реализации печати строковых значений enum, зато без двойного перечисления констант :)
#include <iostream> #include <string> #include <vector> #define MAKE_ENUM(VAR) VAR, #define MAKE_STRINGS(VAR) #VAR, #define MAKE_ENUM_AND_STRINGS(NAME, VARS) \ enum NAME { VARS(MAKE_ENUM) }; \ const std::vector<std::string> NAME##Names { VARS(MAKE_STRINGS) } #define CARD_SUIT_ENUM(DO) \ DO(CLUBS) \ DO(DIAMONDS) \ DO(HEARTS) \ DO(SPADES) #define CARD_RANK_ENUM(DO) \ DO(SIX) \ DO(SEVEN) \ DO(EIGHT) \ DO(NINE) \ DO(TEN) \ DO(JACK) \ DO(QUEEN) \ DO(KING) \ DO(ACE) MAKE_ENUM_AND_STRINGS(CardSuit, CARD_SUIT_ENUM); MAKE_ENUM_AND_STRINGS(CardRank, CARD_RANK_ENUM); void Print(const CardSuit suit, const CardRank rank) { std::cout << CardSuitNames[suit] << " " << CardRankNames[rank] << std::endl; } int main() { Print(DIAMONDS, ACE); std::cin.get(); return 0; }
2. В текстовом файле сделать выборку слов (длиной более 2 символов), состоящих из одинаковых букв. Предполагается, что слова состоят только из печатаемых символов.
#include <iostream> #include <fstream> #include <string> using namespace std; bool equalLetters(string s) { for (int i=0; i<s.size()-1; i++) if(s[i]!=s[i+1]) return false; return true; } int main() { ifstream file; file.open("data.txt"); if (!file) { cout << "Can't open file data.txt"; cin.get(); return 1; } string word; while (file >> word) { if (word.size()>2 && equalLetters(word)) cout << word << endl; } file.close(); cin.get(); return 0; }
3. Задано имя файла, в котором в один столбец записаны целые числа. Программа сортирует числа из файла и записывает их в другой файл в один столбец.
#include <iostream> #include <fstream> #include <set> #include <algorithm> #include <iterator> int main(void) { std::fstream ifs("data.txt", std::ios::in), ofs("data2.txt", std::ios::out); std::multiset<int> mst{ std::istream_iterator<int>(ifs),{} }; std::copy(mst.begin(), mst.end(), std::ostream_iterator<int>(ofs, "\n")); std::cin.get(); return 0; }
4. Дана последовательность (или массив) целых значений а1, ..., an.
В начале последовательности имеется несколько одинаковых между собой значений.
Найти количество этих значений, не используя условного оператора.
#include <iostream> using namespace std; int main(void) { const int n = 6; int a[n] = { 2, 2, 2, 2, 3, 2 }; int i=0; while (i<n-1 && a[i]==a[i+1]) i++; cout << i+1; cin.get(); return 0; }
5. Вывести только те значения элементов целочисленного массива, которые встречаются в нём более одного раза, при этом, каждое значение должно быть распечатано только один раз.
Элементы следует распечатывать в том порядке, в котором они впервые встречаются в массиве.
Массив менять нельзя. Создавать новые массивы также нельзя.
#include <iostream> using namespace std; int main(void) { const int n = 8; int a[n] = { 4, 3, 5, 2, 5, 1, 3, 5 }; for (int i=0; i<n; i++) { bool flag=false; //Элемент уже был раньше? for (int k=0; k<i; k++) if (a[k]==a[i]) { flag = true; break; } //Если нет, то ищем, нет ли повтора дальше if (!flag) for (int j=i+1; j<n; j++) if (a[i]==a[j]) { cout << a[i] << " "; break; } } cin.get(); return 0; }
6. В текстовом файле записана информация о продолжительности телефонных звонков. Информация о каждом звонке записана в отдельной строке в формате "Фамилия:Продолжительность
". Продолжительность указана в секундах. Написать программу, находящую суммарную продолжительность разговоров для каждого из абонентов.
#include <iostream> #include <fstream> #include <vector> #include <string> #include <algorithm> #include <iterator> #include <map> using namespace std; int main(void) { ifstream f("data.txt"); if (!f) { cout << "Can't open data.txt"; cin.get(); return 1; } vector <string> data; copy(istream_iterator<string>(f),istream_iterator<string>(),back_inserter(data)); f.close(); string delimiter = ":"; map <string,int> results; for (int i = 0; i < data.size(); i++) { int pos = data[i].find_first_of(':'); if (pos == string::npos) { cout << "Bad data format in line " << (i+1) << " of data.txt: no :"; cin.get(); return 2; } string name = data[i].substr(0, pos); int sum = stoi(data[i].substr(pos + 1)); if (sum <= 0) { cout << "Bad data format in line " << (i + 1) << " of data.txt: no correct number"; cin.get(); return 3; } results[name] += sum; } for (map<string, int>::iterator it = results.begin(); it != results.end(); ++it) cout << it->first << " = " << it->second << endl; cin.get(); return 0; }
Тестовый файл data.txt:
Ivanov:123 Petrov:4 Popov:56 Ivanov:78 Popov:11
В строках не должно быть пробелов, они будут восприняты как разделители.
Вывод приложения:
Ivanov = 201 Petrov = 4 Popov = 67
7. Текстовый файл содержит строки вида "Фамилия Имя Отчество СреднийБалл
", где СреднийБалл
- вещественное число.
Отсортировать файл по убыванию оценки.
В этой задаче мы читаем строки файла в вектор "целиком", включая все пробелы. Разбор строки простейший, в её конце после числа не должно быть пробелов.
#include <iostream> #include <fstream> #include <vector> #include <string> #include <algorithm> #include <iterator> using namespace std; double parse(string s) { int pos = s.find_last_of(' '); if (pos == string::npos) return 0; string name = s.substr(0, pos); return stod(s.substr(pos + 1)); } int main(void) { ifstream f("data.txt"); if (!f) { cout << "Can't open data.txt"; cin.get(); return 1; } vector <string> data; string line; while (getline(f, line)) data.push_back(line); f.close(); sort(data.begin(), data.end(), [&](const string &a, const string &b) { return parse(a) > parse(b); }); for (vector <string>::iterator it = data.begin(); it != data.end(); ++it) cout << *it << endl; cin.get(); return 0; }
Тестовый файл data.txt:
Ivanov Ivan Pertovich 3.5 Alex Alex Alex 4.25 Petrova Alina Ivanovna 4 Popov Boris Sergeevich 2.71
Вывод приложения:
Alex Alex Alex 4.25 Petrova Alina Ivanovna 4 Ivanov Ivan Pertovich 3.5 Popov Boris Sergeevich 2.71
8. Многопоточный поиск простых чисел с выводом в консоль.
#include <iostream> #include <thread> #include <mutex> #include <vector> #include <functional> #include <fstream> #include <cmath> using namespace std; mutex mtx; void writePrimesToConsole(unsigned int begin, unsigned int end) { for (unsigned int i = begin; i <= end; i++) { for (unsigned int j = 2; j < i; j++) { if (i % j == 0) { break; } else if (j + 1 == i) { mtx.lock(); cout << i << endl; mtx.unlock(); } } } } void callWritePrimesMultipleThreads(unsigned int begin, unsigned int end, unsigned int N) { clock_t startTimer, stopTimer; startTimer = clock(); vector<thread> arr; unsigned int each = end / N; unsigned int start = begin; unsigned int finish = start + each - 1; for (unsigned int i = 0; i < N; i++) { arr.emplace_back(writePrimesToConsole, start, finish); start += each; finish += each; } for (auto& thread : arr) { thread.join(); } stopTimer = clock(); cout << "The time that takes is: " << (double)(stopTimer - startTimer) / CLOCKS_PER_SEC << endl; } int main() { callWritePrimesMultipleThreads(1, 1000, 10); //От 1 до 1000 в 10 потоков cin.get(); return 0; }
9. Составить программу для вычеркивания из строки string
всех букв, стоящих на нечетных местах после буквы "a
".
Если под "вычеркнуть" понимать просто "удалить", то изменится длина строки и, соответственно, нумерация символов в ней.
Стандартный алгоритм вроде copy_if
с таким условием тоже как-то не сообразишь сразу.
Наверное, проще всего переписать посимвольно в новую строку.
#include <iostream> #include <string> using namespace std; int main() { string s1("all, i am a string for a test!"); //номера 012345678901234567890123456789 //удалит * * string s2; for (int i = 0; i < s1.size(); i++) { //Нумерация позиций на самом деле с нуля, и позиция ноль - чётная! if (!(i%2==1 && s1[i-1]=='a')) s2 += s1[i]; } cout << s2; cin.get(); return 0; }
10. Подсчитать в строке string
процент слов, начинающихся с заданной латинской буквы, например, "b
".
#include <iostream> #include <string> #include <sstream> #include <cctype> using namespace std; int main() { string s("Bebeka-memeka, ti v bare bila?"); stringstream ss(s); int words = 0, cnt = 0; while (ss >> s) { if (tolower(s[0]) == 'b') cnt++; words++; } cout << (double)cnt / words * 100 << "%"; cin.get(); return 0; }
11. Запросить, есть ли у пользователя водительские права. Если есть, то ввести по запросу его водительскую категорию и вывести на экран сообщение "Вы имеете водительские права категории ...". Выполнить все необходимые проверки корректности ввода из консоли.
Ради последней фразы и вот такая маленькая программка, возможно, не оптимальная.
#include <iostream> #include <string> using namespace std; template <typename T> void input(char *msg, T &val, T a, T b) { bool valid = false; cout << msg << " "; while (!valid) { valid = true; cin >> val; if (cin.fail() || val<a || val>b) { cin.clear(); cin.ignore(numeric_limits<streamsize>::max(), '\n'); if (valid) { cout << "Error! Please, type it again" << endl; cout << msg << " "; } valid = false; } } } int main() { int prava; input ("Prava e (0/1)?",prava,0,1); if (prava) { char category; input("Category e (A-E)?", category, 'A', 'E'); cout << "Your Category is " << category; } cin.get(); cin.get(); return 0; }
Пример лога запуска:
Prava e (0/1)? Yes Error! Please, type it again Prava e (0/1)? 1 Category e (A-E)? Fuck You! Error! Please, type it again Category e (A-E)? a Error! Please, type it again Category e (A-E)? A Your Category is A
12. Написать программу, которая считает, сколько раз встречается та или иная буква (например, "а
") в текстовом файле.
#include <iostream> #include <fstream> #include <string> #include <algorithm> using namespace std; int main() { ifstream f("data.txt"); if (!f) { cout << "Can't open data.txt"; cin.get(); return 1; } string line; char letter = 'a'; int cnt = 0; while (getline(f, line)) { cnt += count(line.begin(), line.end(), letter); } f.close(); cout << cnt; cin.get(); return 0; }
Файл с именем data.txt
открывается из текущей папки проекта.
13. По заданным пути к папке (Windows), маске для поиска файлов и имени результирующего файла вывести в консоль и файл список найденных файлов (папок) и из размеры.
#include <Windows.h> #include <iostream> #include <fstream> using namespace std; int main() { WIN32_FIND_DATA file; string path = ".\\"; //путь string mask = "*.*"; //маска string searchfiles = path+mask; ofstream ofile("output.txt"); //выходной файл LPSTR lpstr = const_cast<char *>(searchfiles.c_str()); HANDLE search_handle = FindFirstFile(lpstr, &file); if (search_handle) { do { cout << file.cFileName << " " << file.nFileSizeLow << endl; ofile << file.cFileName << " " << file.nFileSizeLow << endl; } while (FindNextFile(search_handle, &file)); FindClose(search_handle); } ofile.close(); cin.get(); return 0; }
14. В университете уездного города N есть n аудиторий, пронумерованных от 1 до n. Студент опаздывает на лекцию, но забыл номер аудитории - помнит, что номер состоит только из цифр x и y. Сколько аудиторий в худшем случае придётся обойти студенту, чтобы найти нужную?
Обратите внимание, что:
- в университете нет аудиторий с ведущими нулями в номере;
- возможно, что в номере аудитории встречается только одна цифра из двух заданных;
- одна и та же цифра может повторяться несколько раз;
- числа x и y могут быть одинаковыми.
По сути, достаточно проверить, состоит ли целое число только из набора заданных цифр.
#include <iostream> using namespace std; bool numberFromDigits(int x, int m, int *d) { //состоит ли число x только из цифр d[m] while (x != 0) { int digit = x % 10; bool found = false; for (int i=0; i<m; i++) if (digit == d[i]) { found = true; break; } if (!found) return false; x /= 10; } return true; } int main() { const int n = 24; int d[2] = { 3, 2 }; int cnt = 0; for (int i = 1; i <= n; i++) if (numberFromDigits(i,2,d)) { cout << i << " "; cnt++; } cout << endl << cnt; cin.get(); return 0; }
15. Найти самое длинное слово (слова) в заданной строке Си. Слова разделены пробелами. Разрешается использовать только strlen
и посимвольное сканирование строки.
Если ничего нельзя использовать, можно попробовать 2 "ручных" прохода по строке.
Тогда имеет смысл при первом проходе найти maxlen
(максимальную длину слова), а при втором, как только попадётся слово с длиной len==maxlen
, напечатать его.
Если разделители - только пробелы а всё остальное - это части слов, то имеем код
#include <iostream> #include <cstdio> #include <cstring> using namespace std; int main() { char s[100]; printf("vvedi predlojenie\n"); gets_s(s); int n = strlen(s); int len = 0; int maxlen = 0; int pos = 0; for (int i = 0; i < n; i++) { char c = s[i]; if (c == ' ') { //или дописать другие разделители в условие if (len>maxlen) { maxlen = len; pos = i; } len = 0; } else { len++; } } if (len>maxlen) { //если последнее слово - ответ maxlen = len; pos = n - maxlen; } cout << "Maxlen=" << maxlen << endl; for (int i = 0; i < n; i++) { char c = s[i]; if (c == ' ') { //или дописать другие разделители в условие if (len == maxlen) { for (int j=i-maxlen; j<i; j++) cout << s[j]; cout << endl; } len = 0; } else { len++; } } if (len == maxlen) { for (int j = n - maxlen; j<n; j++) cout << s[j]; } getchar(); return 0; }
Тест:
vvedi predlojenie Nuka piva nada mnoga shiroka u nas doroga! Maxlen=7 shiroka doroga!
16. Для заданного натурального значения n
составить программу для нахождения цифрового корня числа. Цифровой корень числа получается следующим образом: все цифры числа складываются и цифровой корень находится от получившейся суммы. Процесс повторяется, пока не получится число из одной цифры, которое и есть цифровой корень от исходного значения.
#include <iostream> using namespace std; unsigned int DigitSum(unsigned int n) { unsigned int sum = 0; while (n) { sum += n % 10; n /= 10; } return sum; } unsigned int DigitRoot(const unsigned int &n) { unsigned int root = DigitSum(n); while (root > 9) root = DigitSum(root); return root; } int main() { unsigned int n = 2018; cout << DigitRoot(n); cin.get(); return 0; }
25.04.2018, 10:00 [2951 просмотр]