Да, ваш автомат не прав, так как он не принимает строку ab или пустую строку в этом отношении.Вы получаете следующие последовательности состояний машины:
- q0 Z
a q0 AZ
b q1 AZ
(doesn't accept)
- q0 Z
(doesn't accept)
Поскольку q1 не принимает, ваша машина не может принять ab, то есть на языке, который вы описываете.
У вас есть правоОбщая идея: добавьте A для каждого a, который вы видите, а затем удалите A для каждой группы из 1, 2 или 3 b, которые вы видите.Эта формулировка явно недетерминирована, но мы будем считать, что это нормально, если только DPDA не запрашивается.
(q0, a, Z) => (q0, AZ)
(q0, a, A) => (q0, AA)
(q0, -, Z) => (q1, Z)
(q0, -, A) => (q1, A)
Эти переходы подсчитывают a и добавляют A в стек.Когда вы закончите читать a, мы можем перейти к следующему состоянию, q1, и начать считать b и выталкивать буквы A.
(q1, -, A) => (q2, A)
(q1, -, A) => (q3, A)
(q1, -, A) => (q4, A)
Эти переходы позволяют машине недетерминированно выбирать, считать ли один, два,или три b для конкретного A.
(q2, b, A) => (q1, -)
(q3, b, A) => (q5, A)
(q5, b, A) => (q1, -)
(q4, b, A) => (q6, A)
(q6, b, A) => (q7, A)
(q7, b, A) => (q1, -)
Эти переходы фактически обрабатывают подсчет одного, двух или трех b и удаление A, возвращаясь к q1, чтобы позволить удаление дополнительных A из стека.
(q1, -, Z) => (qf, Z)
Этот переход позволяет КПК принимать строки после того, как стек A исчерпан.Обратите внимание, что если на входе остаются какие-либо b, КПК будет зависать в qf, поскольку там не определены переходы;и так как он аварийно завершает работу, строка не принимается (даже если стек пуст и происходит сбой в состоянии принятия).
Другой подход к этой проблеме - создать CFG для этого языка, а затем создатьпарсер сверху вниз или снизу вверх.Простой язык CFG для этого языка:
S := aSb | aSbb | aSbbb
Если требуется DPDA, это более сложная проблема, и ответ на нее может быть «DPDA не существует».Если честно, я не задумывался над созданием DPDA для этого языка.