Поиск по этому блогу

вторник, 15 марта 2011 г.

Opencup.ru - Northern Grand Prix


В минувшее воскресенье 13.03.2011 на довольно-таки известном сайте по программированию opencup.ru проводился турнир Northern Grand Prix, участником которого был и я. Необходимо было решить 10 задач, на которые отводилось 5 часов.

У большинства людей бытует мнение, что турниры/олимпиады по программированию представляют из-за себя решение очень сложных задач. В большинстве своем - это так. Однако, хочется сказать, что практически всегда бывают задачи, которые не требуют наличия большого количества знаний и являются не такими уж и сложными. Несколько таких задач из прошедшего турнира я решил разместить здесь.

Investments

Профессор Громов разработал проект нового робота. Однако для производства первой партии роботов необходима сумма  денег, которая у профессора отсутствует, так что профессор вынужден привлекать инвестиции, чтобы покрыть расходы на выпуск первой партии.

Профессору известно, сколько компаний готовы поддержать его новую разработку и сколько денег они готовы в нее инвестировать. Профессор хочет привлечь к работе над проектом как можно меньше компаний, а если расходы всех инвесторов не в состоянии покрыть стоимость выпуска первой партии - отказаться от проекта как от малоэффективного.

Необходимо помочь профессору вычислить, какое наименьшее количество компаний он должен привлечь для финансирования нового проекта.


Формат входного файла:
Первая строка содержит целое число T - количество тестовых примеров (1   255). Каждый тестовый пример описывает новый проект. Первая строка описания содержит два числа: стоимость проекта N (1   106), которую надо покрыть за счёт инвестиций и количество потенциальных инвесторов C (1   1000). Вторая строка содержит C целых чисел, i-e из которых задает максимальную сумму Mi, которую i-я компания готова вложить в проект.

Формат выходного файла:
Для каждого тестового примера необходимо вывести одну строку - наименьшее количество инвесторов, которое следует привлечь профессору Громову для того, чтобы начать производство. Если денег на проект не хватит ни при каком количестве инвесторов, необходимо вывести "impossible".

Пример:

Входной файл:
3
101 6
23 27 41 19 23 57
100 7
20 22 33 8 24 67 9
1001 3
123 456 123

Выходной файл:
3
2
impossible

Решение:
Задачка является довольно-таки простой. Для того, чтобы получить минимальное количество инвесторов, мы должны выбрать тех, которые готовы вложить в проект максимальные суммы денег.
  1. #include <stdio.h>
  2. #include <algorithm>
  3. using namespace std;

  4. int main()
  5. {
  6.         FILE *in, *out;
  7.         // количество тестовых примеров
  8.         int T(0);
  9.         // стоимость проекта и количество потенциальных инвесторов соответственно
  10.         int N (1), C(1);

  11.         in = fopen("invest.in", "r");
  12.         fscanf(in, "%d", &T);
  13.         out = fopen("invest.out", "w");

  14.         // каждый тестовый пример будем обрабатывать отдельно
  15.         // и сразу же записывать результат в файл
  16.         for(int i = 0; i < T; i++)
  17.         {
  18.                 // массив сумм, которые готовы предоставить инвесторы
  19.                 int M[1000] = {0};
  20.                 
  21.                 fscanf(in, "%d %d", &N, &C);
  22.                 for(int i = 0; i < C; i++)
  23.                         fscanf(in, "%d", &M[i]);

  24.                 // сортируем суммы, которые готовы
  25.                 // предоставить инвесторы, по возрастанию
  26.                 sort(M, M+C);

  27.                 // минимальное количество инвесторов,
  28.                 // которое следует привлечь профессору
  29.                 int count = 0;
  30.                  // сумма, которую готовы предоставить эти инвесторы
  31.                 int sum = 0;

  32.                 /* увеличиваем сумму инвестиций до тех пор,
  33.                 пока она не превысит/не станет равной требуемой сумме инвестиций,
  34.                 или же пока не переберем всех инвесторов;
  35.                 начинаем брать суммы с конца, так как они максимальны,
  36.                 а, следовательно, количество инвесторов будет минимальным */
  37.                 for(int i = C-1; i >= 0; i--)
  38.                 {
  39.                         sum += M[i];
  40.                         count++;
  41.                         if(sum >= N)
  42.                                 break;
  43.                 }

  44.                 /* если общая сумма, которую могут предоставить инвесторы
  45.                 меньше требуемой суммы, то выводим "impossible",
  46.                 иначе выводим требуемое количество инвесторов */
  47.                 if(sum < N)
  48.                         fprintf(out, "impossible\n");
  49.                 else
  50.                         fprintf(out, "%d\n", count);
  51.         }

  52.         fclose(in);
  53.         fclose(out);

  54.         return 0;
  55. }
OCR

Для нового поколения роботов профессора Громова компания-поставщик разработала улучшенный модуль распознавания символов (OCR). Подобные модули используются при чтении роботом "бумажного" текста. К сожалению, распознавание не всегда работает успешно, так что некоторые символы остаются нераспознанными. Наша задача - вычислить коэффициент распознавания. Коэффициент распознавания определяется как R/A * 100%, где R - количество распознанных символов и А общее количество символов в тексте. При этом переводы строк символами не считаются.

Формат входного файла:
Входной файл содержит как минимум одну непустую строку распознанного текста. Нераспознанные символы представлены символом "#". При этом длина строки не превосходит 100 символов, строки содержат только символы с ASCII-кодами от 32 до 126 включительно, при этом "#" не встречается в исходном тексте.

Формат выходного файла:
Необходимо вывести коэффициент распознавания (в %), округлённый до ближайшего числа, десятичная запись которого содержит не более одного знака после точки (0.05 округляется до 0.1). При этом лишние нули после точки выводить запрещено (то есть вывод 0.50 вместо 0.5 или 25.0 вместо 25 будет признан некорректным).

Пример:

Входной файл:
Pr#nt the r#tio in perce##,
rounde##to t#e nearest number.

Professor Gromov.

Выходной файл:
87.7

100

Решение:
Сложность данной задачи состоит лишь в правильном подсчёте всех символов строки и округлении результирующего значения. Довольно-таки просто ее решить, если знать некоторые технические аспекты и средства языка С++.

В данном случае, считывание текста из файла и запись в файл необходимо осуществлять с помощью потоков ifstream и ofstream из библиотеки fstream в переменную типа string из библиотеки string, а для указания точности выводимого результата использовать функцию setprecision из библиотеки iomanip. Она выводит указанное количество символов и при необходимости округляет число.
  1. #include <fstream>
  2. #include <string>
  3. #include <iomanip>
  4. using namespace std;

  5. int main()
  6. {
  7.         ifstream cin("ocr.in");
  8.         ofstream cout("ocr.out");

  9.         // буфер, необходимый для считывания каждой строки, 
  10.         // и итоговая строка соответственно
  11.         string bufer, str;
  12.         // считываем данные из файла построчно в буфер
  13.         // и формируем итоговую строку
  14.         while(!cin.eof())
  15.         {
  16.                 getline(cin, bufer);
  17.                 str.append(bufer);
  18.         }

  19.         // длина исходного текста
  20.         int m = str.length();
  21.         // количество нераспознанных символов
  22.         int count (0);

  23.         // проходим по итоговой строке и подсчитываем количество символов "#"
  24.         for(int i = 0; i < m; i++)
  25.                 if(str[i] == '#')
  26.                         count++;

  27.         // подставляем данные в исходную формулу
  28.         float result = (float)(m - count) / (float)m * 100;

  29.         /* если коэффициент распознавания больше десяти,
  30.         то нам необходимо вывести число, состоящее из 3 цифр:
  31.         2 первые цифры - целая часть, 3-я цифра - дробная часть;
  32.         если коэффициент распознавания меньше либо равен десяти,
  33.         то нам необходимо вывести число, состоящее из 2 цифр:
  34.         1-ая цифра - целая часть, 2-ая цифра - дробная часть,
  35.         для числа 10 - 2 цифры представляют целую часть */
  36.         if(result > 10)
  37.                 cout << setprecision(3) << result;
  38.         else
  39.                 cout << setprecision(2) << result;

  40.         cin.close();
  41.         cout.close();

  42.         return 0;
  43. }
Spinity

Некоторые строчные латинские буквы обладают следующим свойством: при повороте на 180 градусов они переходят или сами в себя, или в другие буквы. Можно составить даже целые слова, которые будут переходить сами в себя при повороте на 180 градусов, например, "sos" или "mow". Введем для слова w параметр "вращаемость" Sp(w) следующим образом:

Будем считать, что буквы 'o', 'l', 's', 'x' автосимметричны при повороте, и что существуют следующие пары взаимно симметричных букв: 'b' и 'q', 'd' и 'p', 'm' и 'w', 'n' и 'u'.

Для двух букв c1 и c2 s(c1c2) равно 3, если буквы совпадают и являются автосимметричными, 2, если буквы не совпадают, но составляют симметричную пару, 1, если буквы совпадают, но не являются автосимметричными, и 0 в оставшихся случаях.

Наконец, определим вращаемость Sp(w) как сумму значений функции s для симметрично расположенных пар букв: для n-буквенного слова w Sp(w) = s(w1, wn) + s(w2, wn-1) + ... + s(wn, w1).

Наша задача - для каждого из заданных слов вычислить его вращаемость.

Формат входного файла:
Входной файл состоит из не более, чем 100, и не менее, чем одного слова. Каждое слово расположено в отдельной строке и состоит из не менее, чем 1, но не более, чем 10 строчных латинских букв.

Формат выходного файла:
Для каждого слова из входного файла необходимо вывести в отдельной строке само это слово и его вращаемость в соответствии с форматом, указанным в примере. Результаты выводить в том порядке, в котором слова следуют во входном файле.

Пример:

Входной файл:
spellers
ololo
meow
axe
pad
sos
nu

Выходной файл:
spellers 14
ololo 15
meow 4
axe 3
pad 5
sos 9
nu 4

Решение:
Решение данной задачи заложено в её условии. Необходимо лишь аккуратно его закодировать.

Функция s определяет вес пары букв согласно поставленным условиям. Функция Sp подсчитывает сумму весов для симметрично расположенных пар букв проверяемого слова.
  1. #include <stdio.h>
  2. #include <string.h>

  3. int Sp(char*);
  4. int s(char, char);

  5. int main()
  6. {
  7.         FILE *in, *out;
  8.         // проверяемое слово
  9.         char *str = new char[11];

  10.         in = fopen("spinity.in", "r");
  11.         out = fopen("spinity.out", "w");

  12.         // считывает по одному слову из файла,
  13.         // подсчитываем его вращаемость
  14.         // и сразу же записываем результат в файл
  15.         while(fscanf(in, "%s", str) != EOF)
  16.         {
  17.                 fprintf(out, "%s %d\n", str, Sp(str));
  18.         }

  19.         fclose(in);
  20.         fclose(out);

  21.         return 0;
  22. }

  23. int Sp(char *str)
  24. {
  25.         // вращаемость слова как сумма значений функции s
  26.         int sum = 0;

  27.         // перебираем симметрично расположенные пары букв
  28.         // и для каждой пары вызываем функцию s
  29.         for(int i = 0; i < strlen(str); i++)
  30.                 sum += s(str[i], str[strlen(str)-1-i]);

  31.         return sum;
  32. }

  33. int s(char c1, char c2)
  34. {
  35.         // если буквы совпадают и являются автосимметричными
  36.         if(((c1 == 'o') && (c2 == 'o')) || ((c1 == 'l') && (c2 == 'l')) ||
  37.            ((c1 == 's') && (c2 == 's')) || ((c1 == 'x') && (c2 == 'x')))
  38.                 return 3;
  39.         // если буквы не совпадают, но составляют симметричную пару
  40.         else if((((c1 == 'b') && (c2 == 'q')) || ((c2 == 'b') && (c1 == 'q'))) ||
  41.                   (((c1 == 'd') && (c2 == 'p')) || ((c2 == 'd') && (c1 == 'p'))) ||
  42.                   (((c1 == 'm') && (c2 == 'w')) || ((c2 == 'm') && (c1 == 'w'))) ||
  43.                   (((c1 == 'n') && (c2 == 'u')) || ((c2 == 'n') && (c1 == 'u'))))
  44.                 return 2;
  45.         // если буквы совпадают, но не являются автосимметричными
  46.         else if(c1 == c2)
  47.                 return 1;
  48.         // во всех остальных случаях
  49.         else
  50.                 return 0;
  51. }

Комментариев нет:

Отправить комментарий