Задача
Есть несколько способов, чтобы перетасовать колоду карт. Одним из таких примеров является перетасовка для японской карточной игры «Ханафуда». Ниже показано, как ее выполнить.
Имеется колода из $n$ карт. Начиная с $p$-ой карты сверху, $c$ карт вынимаются и кладутся на вершину колоды, как показано на рисунке. Такую операцию назовем операциею срезки.
Напишите программу, которая моделирует перетасовку Ханафуда, и выведет номер карты, которая в конце будет находиться наверху.
Входные данные
Состоит из нескольких тестов. Каждый тест начинается со строки, содержащей два натуральных числа $n$ $(1 ≤ n ≤ 50)$ и $r$ $(1 ≤ r ≤ 50)$ — количество карт в колоде и количество операций срезания.
Каждая из следующих $r$ строк описывает операцию срезания. Они выполняются в перечисленном порядке. Каждая строка содержит два натуральных числа $p$ и $c$ $(p + c ≤ n + 1)$. Начиная с $p$-ой карты сверху, c карт вытаскиваются и кладутся наверх.
Последняя строка содержит два нуля.
Выходные данные
Для каждого теста вывести в отдельной строке номер верхней карты после выполнения тасования. Считайте, что сначала карты пронумерованы числами от $1$ до $n$ снизу доверху.
Тесты
№ | Входные данные | Выходные данные |
1 |
5 2 3 1 3 1 10 3 1 10 10 1 8 3 0 0 |
4 4 |
Код
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
#include <iostream> #include <string> using namespace std; struct Comma { int num, pos; Comma() { num = 0; pos = 0; } }; int main() { int n, r; while(cin >> n >> r) { int p, c; string s; // Filling the array with cards' numbers separated by comma for (int i = n; i > 0; i--) s += (i == 1 ? to_string(1) : to_string(i) + ","); if (n > 0) { for (int i = 0; i < r; i++) { cin >> p >> c; // Create object with number of comma in string and its position Comma comma1, comma2; int s_len = s.length(); if (p != 1) { // -------- Looking for indexes of needed commas to pick 'c' cards for (int j = 0; j < s_len; j++) { if (comma1.num == p-1) { comma1.pos = j; comma1.num = 0; } if (comma2.num == p+c-1) { comma2.pos = j; comma2.num = 0; } if (comma1.pos == 0 && s[j] == ',') comma1.num += 1; if (comma2.pos == 0 && s[j] == ',') comma2.num += 1; } // --------------------------------------------------------------- // --------- Swapping cards --------- string s1 = s.substr(comma1.pos, comma2.pos - comma1.pos); s.erase(comma1.pos, comma2.pos - comma1.pos); if (s1[s1.length()-1] != ',') s = s1 + ',' + s; else s = s1 + s; // ---------------------------------- } } int k = 0; while (s[k] != ',') k++; string res = s.substr(0, k); cout << res << "\n"; } } } |
Решение
Решить данную задачу можно несколькими способами. Первая мысль, которая мне пришла в голову — поместить все числа в строку и совершать тасование с помощью методов работы со строками, такими как $erase$ и $substr$. В течении решения стало понятно, что просто записывать числа в строку будет неправильно, так как возможны и двузначные числа. Так как неизвестно какое число будет следующим (однозначное или двузначное), особенно после нескольких перестановок, появляется идея хранить в строке числа, разделенные между собой запятыми. И в дальнейшем, если мне понадобится вытащить 5 карт из колоды начиная с 17, то я дойду до 16 запятой и возьму все, что хранится после нее, до 17+5 запятой и переставлю эти числа в начало строки (наверх колоды). Также в процессе поиска позиции необходимой запятой мне нужно получить ее позицию в строке, поэтому я решил создать структуру $Comma$, которая будет хранить номер запятой в строке и ее позицию относительно всех символов в данной строке, чтобы использовать ее во время каждой перестановки.
Таким образом, получаем рабочее решение данной задачи.
P.S. Новые решения согласно советам преподавателя
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#include <iostream> #include <string> using namespace std; int main() { int n, r; while(cin >> n >> r) { int p, c; string s; for (int i = n; i > 0; i--) s += (char)i; if (n > 0) { for (int i = 0; i < r; i++) { cin >> p >> c; if (p != 1) { string s1 = s.substr(p-1, c); s.erase(p-1, c); s = s1 + s; } } cout << (int)s[0] << "\n"; } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
#include <iostream> using namespace std; struct Card { int number; Card *next; Card(int num, Card *nxt = 0) { number = num; next = nxt; }; }; int main() { int n, r; Card *top_card = 0; while(cin >> n >> r) { int p, c; for (int i = 1; i <= n; i++) { top_card = new Card(i, top_card); }; if (n > 0) { for (int i = 0; i < r; i++) { cin >> p >> c; if (p != 1) { Card *first_moving = 0, *last_moving = 0, *last_before_moving = top_card; for (int j = 1; j < p - 1; j++) { last_before_moving = last_before_moving->next; } first_moving = last_before_moving->next; last_moving = first_moving; for (int j = 1; j < c; j++) { last_moving = last_moving->next; } last_before_moving->next = last_moving->next; last_moving->next = top_card; top_card = first_moving; } } cout << top_card->number << "\n"; } } } |
Ссылки
- Код на Ideone
- Задача на E-olymp
- Засчитанное решение (со строками)
- Засчитанное решение (с преобразованием чисел в соответствующие ASCII коды)
- Засчитанное решение (со связным списком)
Для отправки комментария необходимо войти на сайт.