Задача №1701. Модель Крипке
Тестирование и контроль качества являются чрезвычайно трудоемкими этапами разработки ПО. Для облегчения этой задачи используются несколько различных техник. Одна из них называется верификацией. Model checking — верификация на базе модели Крипке.
Модель Крипке представляет собой набор \((P, S, R, L)\), где \(P\) – конечное множество высказываний, \(S\) — конечное множество состояний модели, \(R \in SxS\) – переход из одного состояния в другое. \(L \in SхP\) – отношение истинности (высказывание \(P\) в состоянии \(S\) истинно).
Отношение \(R\) будем считать рефлексивным, т.е. \(R(S, S)\) всегда существует.
Набор состояний π, начинающийся в состоянии s, представляет собой бесконечную последовательность состояний \(s_0, s_1,...,\) такую что \(s_0 = s\) и для любого \(i ≥ 0\) выполнено \((s_i s_{i+1})\) представляет собой переход.
В данной модели существует кванторы, применяемые к наборам и к состояниям, с помощью которых образуются формулы (элементарная формула, это высказывание, оно выполняется во всех своих истинных состояниях).
- Af выполняется в состоянии \(s\), если формула \(f\) выполняется для каждого набора, начинающегося в состоянии \(s\);
- Ef выполняется в \(s\), если существует набор, начинающийся в состоянии \(s\), в котором формула \(f\) выполняется.
- Если \(f\) и \(g\) формулы, то
- Gf (Globally) выполняется для набора \(s_0s_1…,\) если для любого \(i ≥ 0\) формула \(f\) выполняется в состоянии \(s_i\);
- fUg (Until) выполняется для набора \(s_0s_1…,\) если существует такое \(i ≥ 0\), что \(f\) выполняется для всех состояний \(s_0;s_1;…; si-1,\) и \(g\) выполняется в состоянии \(s_i\).
Проверить формулу \(f\) – означает найти все состояния, для которых она выполняется. Для произвольной формулы это сделать сложно. Ваша задача проще – проверить формулу E(xU(AGy)), где \(x\) и \(y\) - высказывания.
Первая строка содержит три натуральных числа \(n, m\) и \(k (1 ≤ n ≤ 10 000; 0 ≤ m ≤ 100 000; 1 ≤ k ≤ 26)\) – число состояний, переходов и высказываний. Каждая из следующих \(n\) строк описывает одно из состояний. Состояние \(i (1 ≤ i ≤ n)\) описывается числом \(c_i (0 ≤ c_i ≤ k)\) – количеством высказываний, которые истинны в этом состоянии, затем через пробел перечислены эти высказывания. Сами высказывания обозначаются первыми \(k\) маленькими латинскими буквами.
Следующие \(m\) строк описывают переходы. Каждое описание содержит два числа \(s\) и \(t\)
\((1 ≤ s, t ≤ n; s ≠ t)\) – переход из состояния \(s\) в состояние \(t\). Переходы из \(s\) в \(s\) существуют всегда и во входных данных не отражены. Никакие переходы не упомянуты дважды.
Последняя строка входных данных содержит формулу, которую надо проверить. Она всегда имеет вид E(xU(AGy)), где \(x\) и \(y\) – некоторые высказывания.
Первая строка выходных данных должна содержать число состояний, для которых формула верна. Следующие строки должны содержать номера этих состояний в возрастающем порядке.
7 8 2 1 a 1 a 2 a b 1 b 1 b 1 a 1 a 1 2 2 3 3 4 4 5 5 3 2 6 6 7 7 6 E(aU(AGb))
5 1 2 3 4 5