Матч
301, Исправить расстановку скобок (CorrectingParenthesization)
Дивизион 2, Уровень
3
Имеется строка из скобок.
Требуется изменить наименьшее количество символов так, чтобы полученная строка
была правильной. Удалять или вставлять символы нельзя. Всего существует три
вида скобок: (), [] и {}. Правильная строка определяется следующими правилами:
1. Пустая строка является
правильной.
2. Если строка s правильная, то правильными являются
также (s), [s] и {s}.
3. Если строки s и t
правильные, то правильной будет строка st.
Например, строки “([{}])”,“” и “(){}[]” являются правильными, а “([}]”,“([)]” и “{” – нет.
Класс: CorrectingParenthesization
Метод: int getMinErrors(string s)
Ограничения:
s содержит от 0 до 50 символов, s содержит четное количество символов ‘(’, ‘)’,
‘{’, ‘}’, ‘[’, ‘]’.
Вход. Строка символов s.
Выход. Наименьшее количество символов, которое можно изменить так,
чтобы строка стала правильной.
Пример входа
s |
"([{}])()[]{}" |
"([)]" |
"([{}[]" |
Пример выхода
0
2
1
РЕШЕНИЕ
динамическое программирование
Обозначим через f(i, j)
наименьшее количество символов, которое можно изменить так, чтобы подстрока sisi+1…sj-1sj стала правильной. Тогда
имеют место соотношения:
1. f(i, j) = 0 при i > j, так как в таком случае подстрока будет пустой строкой.
2. f(i, j)
= f(i + 1, j – 1) + enc(si
,sj). Делаем так, чтобы
символ si был
открывающейся скобкой, а sj – соответствующий ему закрывающейся скобкой.
Далее рекурсивно рассматриваем подстроку si+1…sj-1.
Функция enc(si ,sj) возвращает:
а) 0, если символы si и sj являются соответствующими открывающейся и
закрывающейся скобками;
б) 2, если символ si является закрывающейся
скобкой, а sj –
открывающейся;
в) 1 иначе. В этом случае
достаточно изменить один из символов si или sj так, чтобы они образовали
правильную скобочную пару;
3. f(i, j)
= (f(i, k) + f(k+1, j)). Подстроку sisi+1…sj-1sj рассматриваем как
последовательность двух правильных скобочных
структур: si…sk
и sk+1…sj.
В ячейках m[i][j]
массива m сохраняем значения f(i, j). Ответом задачи будет f(0, |s| – 1), где s – входная строка.
ПРОГРАММА
#include <cstdio>
#include <string>
#include <memory>
#define min(i,j) (i < j) ? i : j
using namespace std;
int m[51][51];
string s;
int enc(char c, char d)
{
string p = "([{)]}";
if (p.find(c) / 3 > 0 && p.find(d) / 3
< 1) return 2;
if (p.find(c) % 3 == p.find(d) % 3 && c != d)
return 0;
return 1;
}
int f(int i, int j)
{
int k;
if (i > j) return
0;
if (m[i][j] >= 0) return
m[i][j];
int r = f(i+1,j-1) + enc(s[i],s[j]);
for(k = i + 1; k < j; k += 2)
r = min(r,f(i,k) + f(k+1,j));
return m[i][j] = r;
}
class CorrectingParenthesization
{
public:
int getMinErrors(string s)
{
::s = s;
memset(m,-1,sizeof(m));
return f(0,s.size() - 1);
}
};