БлогNot. Ещё 16 не пригодившихся задач за апрель 2018

Ещё 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 [2838 просмотров]


теги: учебное список c++ алгоритм

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