Задача №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
Сдать: для сдачи задач необходимо войти в систему