Important Questions - Theory of Computation
Comprehensive Answers to Top 10 Exam Questions
Q1. What is Mealy Machine and Moore Machine?
Answer:
Mealy Machine and Moore Machine are two types of Finite State Transducers (FST) - finite automata with outputs. They differ in how outputs are produced.
Mealy Machine:
Definition:
A Mealy Machine is a 6-tuple M = (Q, Σ, Δ, δ, λ, q₀) where:
- Q: Finite set of states
- Σ: Input alphabet
- Δ: Output alphabet
- δ: Q × Σ → Q: State transition function
- λ: Q × Σ → Δ: Output function (depends on state AND input)
- q₀: Initial state
Key Characteristics of Mealy Machine:
- Output depends on current state AND current input
- Output is associated with transitions (edges)
- Produces output while making state transition
- Generally requires fewer states
- Immediate response to input (no delay)
- Output length = Input length
Example: Mealy Machine
Design a Mealy machine that outputs 1 when it receives two consecutive 1's, otherwise outputs 0.
State Diagram:
States: q₀ (initial), q₁ (seen one 1)
Transitions (format: input/output):
q₀ --0/0--> q₀
q₀ --1/0--> q₁
q₁ --0/0--> q₀
q₁ --1/1--> q₁
Transition Table:
| Current State | Input: 0 | Output | Input: 1 | Output |
|---|---|---|---|---|
| q₀ | q₀ | 0 | q₁ | 0 |
| q₁ | q₀ | 0 | q₁ | 1 |
Example Run:
Input: 01101
- Start: q₀
- Read 0: q₀ → q₀, output 0
- Read 1: q₀ → q₁, output 0
- Read 1: q₁ → q₁, output 1 ✓ (two consecutive 1's)
- Read 0: q₁ → q₀, output 0
- Read 1: q₀ → q₁, output 0
Output: 00100
Moore Machine:
Definition:
A Moore Machine is a 6-tuple M = (Q, Σ, Δ, δ, λ, q₀) where:
- Q: Finite set of states
- Σ: Input alphabet
- Δ: Output alphabet
- δ: Q × Σ → Q: State transition function
- λ: Q → Δ: Output function (depends only on state)
- q₀: Initial state
Key Characteristics of Moore Machine:
- Output depends only on current state
- Output is associated with states (nodes)
- Produces output when entering a state
- May require more states than Mealy machine
- One clock cycle delay in output
- Easier to design and understand
- Output length = Input length + 1 (includes initial state output)
Example: Moore Machine
Design a Moore machine that outputs 1 when it has seen two consecutive 1's, otherwise outputs 0.
State Diagram:
States:
q₀ (initial, output 0)
q₁ (seen one 1, output 0)
q₂ (seen two 1's, output 1)
Transitions:
q₀ --0--> q₀
q₀ --1--> q₁
q₁ --0--> q₀
q₁ --1--> q₂
q₂ --0--> q₀
q₂ --1--> q₂
Outputs:
λ(q₀) = 0
λ(q₁) = 0
λ(q₂) = 1
Transition Table:
| State | Output | Input: 0 | Input: 1 |
|---|---|---|---|
| q₀ | 0 | q₀ | q₁ |
| q₁ | 0 | q₀ | q₂ |
| q₂ | 1 | q₀ | q₂ |
Example Run:
Input: 0110
- Start: q₀, output 0
- Read 0: q₀ → q₀, output 0
- Read 1: q₀ → q₁, output 0
- Read 1: q₁ → q₂, output 1 ✓ (in state that saw two 1's)
- Read 0: q₂ → q₀, output 0
Output: 00010 (5 outputs for 4 inputs)
Detailed Comparison:
| Feature | Mealy Machine | Moore Machine |
|---|---|---|
| Output depends on | Current state + Current input | Current state only |
| Output associated with | Transitions (edges) | States (nodes) |
| Output function | λ: Q × Σ → Δ | λ: Q → Δ |
| Number of states | Generally fewer | May need more |
| Response time | Immediate (synchronous with input) | One cycle delay |
| Output length | Equal to input length | Input length + 1 |
| Design complexity | More complex | Simpler, more intuitive |
| State diagram | Output on edges (transitions) | Output in states (nodes) |
| Transition format | input/output | Only input (output in state) |
| Practical use | When immediate response needed | When delay is acceptable |
Conversion Between Mealy and Moore:
Important: Mealy and Moore machines are equivalent in computational power. Any Mealy machine can be converted to an equivalent Moore machine and vice versa.
Mealy to Moore Conversion:
- For each state q with different outputs for different inputs, create separate states in Moore machine
- Each new state corresponds to a (state, output) pair from Mealy machine
- May increase number of states
Moore to Mealy Conversion:
- Output of Mealy transition = output of destination state in Moore machine
- Generally reduces number of states
- More straightforward conversion
Applications:
- Mealy Machines: Digital circuit design, protocol converters, real-time systems
- Moore Machines: Control systems, sequence detectors, simple state machines
Q2. Explain FSM with Transition Graph and Transition Matrix
Answer:
Finite State Machine (FSM):
A Finite State Machine is a mathematical model of computation consisting of a finite number of states, transitions between those states, and actions. It's the foundation of automata theory.
Formal Definition of FSM:
An FSM is a 5-tuple M = (Q, Σ, δ, q₀, F) where:
- Q: Finite set of states
- Σ: Finite input alphabet
- δ: Q × Σ → Q: Transition function
- q₀ ∈ Q: Initial/start state
- F ⊆ Q: Set of final/accepting states
Components of FSM:
- States (Q): Represent different configurations/conditions of the system
- Input Alphabet (Σ): Set of symbols that the FSM can read
- Transitions (δ): Rules defining how to move from one state to another
- Start State (q₀): Where the FSM begins execution
- Final States (F): States where input is accepted
1. Transition Graph (State Diagram):
A Transition Graph is a visual representation of an FSM using a directed graph.
Components of Transition Graph:
- Circles/Nodes: Represent states
- Arrows/Edges: Represent transitions
- Edge Labels: Input symbols causing transition
- Incoming Arrow: Indicates start state (no source)
- Double Circle: Indicates final/accepting state
Example 1: FSM that accepts strings ending with '01'
Transition Graph:
0 1
┌───────┐ ┌──┐
│ ↓ │ │
→(q₀)──0──→(q₁)
↑ │
│ 1 │
└───────┘
q₁──1──→((q₂))
↑ │
│ 0 │
└──────┘
States: Q = {q₀, q₁, q₂}
Start: q₀ (indicated by →)
Final: q₂ (indicated by double circle (( )))
Alphabet: Σ = {0, 1}
Explanation:
- q₀: Initial state (haven't seen required pattern)
- q₁: Just read a '0' (waiting for '1' to complete '01')
- q₂: Accepting state (string ends with '01')
Transitions:
- From q₀: Read 0 → go to q₁; Read 1 → stay in q₀
- From q₁: Read 0 → stay in q₁; Read 1 → go to q₂
- From q₂: Read 0 → go to q₁; Read 1 → go to q₀
Test Strings:
- "01" → q₀→q₁→q₂ ✓ Accepted
- "101" → q₀→q₀→q₁→q₂ ✓ Accepted
- "001" → q₀→q₁→q₁→q₂ ✓ Accepted
- "10" → q₀→q₀→q₁ ✗ Rejected (ends in q₁)
- "11" → q₀→q₀→q₀ ✗ Rejected (ends in q₀)
2. Transition Matrix (Transition Table):
A Transition Matrix is a tabular representation showing state transitions for each input symbol.
Transition Table for Above FSM:
| Current State | Input: 0 | Input: 1 |
|---|---|---|
| → q₀ | q₁ | q₀ |
| q₁ | q₁ | *q₂ |
| *q₂ | q₁ | q₀ |
Legend:
- → indicates start state
- * indicates final/accepting state
- Each cell shows the next state for given input
Matrix Representation (Mathematical):
For formal mathematical representation, we can use matrices where rows are current states, columns are inputs:
Matrix Form:
For input '0':
M₀ = | q₁ q₁ q₁ |
(states after reading 0 from q₀, q₁, q₂)
For input '1':
M₁ = | q₀ q₂ q₀ |
(states after reading 1 from q₀, q₁, q₂)
Example 2: Even Number of 1's
Design FSM that accepts strings with even number of 1's.
Transition Graph:
1 1
┌─────┐ ┌─────┐
↓ │ ↓ │
→((q₀)) (q₁)
│ ↑ └───┘ ↑
│ └─────────┘
│ 0
└──────────────┐
0 │
↓
States: {q₀ (even), q₁ (odd)}
Start: q₀
Final: {q₀}
Transition Table:
| State | Input: 0 | Input: 1 |
|---|---|---|
| →*q₀ (even 1's) | q₀ | q₁ |
| q₁ (odd 1's) | q₁ | q₀ |
Working:
- Start in q₀ (0 ones = even)
- Every '1' toggles between even/odd
- '0' doesn't affect count
- Accept if end in q₀ (even count)
Examples:
- "011" → even 1's ✓
- "1001" → even 1's ✓
- "0" → even 1's (zero) ✓
- "101" → odd 1's ✗
Example 3: Divisible by 3 (in binary)
FSM that accepts binary numbers divisible by 3.
Transition Table:
| State (Remainder) | Input: 0 | Input: 1 | Meaning |
|---|---|---|---|
| →*q₀ | q₀ | q₁ | Remainder 0 (divisible by 3) |
| q₁ | q₂ | q₀ | Remainder 1 |
| q₂ | q₁ | q₂ | Remainder 2 |
Logic: When reading binary left-to-right, new value = (old_value × 2 + new_bit) mod 3
Examples:
- "11" (3 in decimal) → q₀→q₁→q₀ ✓
- "110" (6 in decimal) → q₀→q₁→q₀→q₀ ✓
- "1001" (9 in decimal) → q₀→q₁→q₂→q₁→q₀ ✓
Advantages of Transition Graph:
- Visual: Easy to understand and design
- Intuitive: Shows flow of computation clearly
- Quick Analysis: Can trace paths visually
- Design Tool: Great for initial design
Advantages of Transition Matrix:
- Compact: Concise representation
- Implementation: Easy to code (2D array/hash table)
- Mathematical: Can use matrix operations
- Complete: Shows all transitions explicitly
Equivalence:
Both representations describe the same FSM - they contain identical information:
- Graph → Table: List all transitions from diagram
- Table → Graph: Draw states and add arrows for each table entry
Applications of FSM:
- Compilers: Lexical analysis (tokenization)
- Network Protocols: TCP state machine
- Digital Circuits: Sequential circuit design
- Game AI: Character behavior (patrol, attack, flee)
- Text Processing: Pattern matching, regular expressions
- Control Systems: Traffic lights, vending machines
Q3. What is Pumping Lemma and Applications of Pumping Lemma?
Answer:
Pumping Lemma for Regular Languages:
The Pumping Lemma is a fundamental property that all regular languages must satisfy. It's primarily used as a tool to prove that certain languages are NOT regular.
Statement of Pumping Lemma:
If L is a regular language, then there exists a constant n (called the pumping length) such that:
For any string w ∈ L where |w| ≥ n, the string w can be divided into three parts w = xyz satisfying ALL of these conditions:
- |y| > 0: The middle part y is non-empty
- |xy| ≤ n: The first two parts xy fit within the first n symbols
- ∀i ≥ 0, xyiz ∈ L: We can "pump" y any number of times (including 0) and the resulting string remains in L
Intuition Behind Pumping Lemma:
Why does this work?
- Regular languages are accepted by DFA with finite states
- If string is long enough (≥ n states), some state must repeat (Pigeonhole Principle)
- The loop between repeated states can be traversed 0, 1, 2, ... times
- This creates the "pumping" behavior
Important Points:
- n is usually the number of states in the DFA
- y represents the loop that can be repeated
- Pumping Lemma is necessary but NOT sufficient - satisfying it doesn't prove regularity!
- Used to prove languages are NOT regular (proof by contradiction)
How to Use Pumping Lemma (Proof Template):
To prove a language L is NOT regular:
- Assume L is regular (for contradiction)
- Let n be the pumping length guaranteed by Pumping Lemma
- Choose a string w ∈ L where |w| ≥ n (choose strategically!)
- Consider all possible divisions w = xyz satisfying conditions 1 and 2
- Show that for ANY such division, there exists an i such that xyiz ∉ L
- Conclude this contradicts Pumping Lemma, so L is NOT regular
Applications of Pumping Lemma:
Application 1: L = {0n1n | n ≥ 0} is NOT Regular
Language: Equal number of 0's followed by equal number of 1's
Examples: ε, 01, 0011, 000111, ...
Proof:
- Assume L is regular with pumping length n
- Choose w = 0n1n (clearly w ∈ L and |w| = 2n ≥ n)
- By Pumping Lemma, w = xyz where:
- |y| > 0
- |xy| ≤ n
- Analysis: Since |xy| ≤ n, both x and y consist only of 0's (they're in the first n symbols)
- So y = 0k for some k > 0
- Pump with i = 2: xy2z = 0n+k1n
- This has MORE 0's than 1's
- Therefore xy2z ∉ L
- Pump with i = 0: xy0z = xz = 0n-k1n
- This has FEWER 0's than 1's
- Therefore xz ∉ L
- Contradiction! Therefore L is NOT regular ✓
Application 2: L = {ap | p is prime} is NOT Regular
Language: Strings of a's where length is a prime number
Examples: aa, aaa, aaaaa, aaaaaaa (lengths 2, 3, 5, 7, ...)
Proof:
- Assume L is regular with pumping length n
- Choose w = ap where p is a prime ≥ n (such prime exists by Euclid)
- By Pumping Lemma, w = xyz where |y| > 0 and |xy| ≤ n
- Let |y| = k where 1 ≤ k ≤ n < p
- Pump with i = p: xypz has length:
- |xyz| + (p-1)|y| = p + (p-1)k = p + pk - k = p(1+k) - k
- If we choose i = p+1: length = p + p·k = p(1+k)
- This is composite (divisible by p and 1+k), not prime!
- Contradiction! Therefore L is NOT regular ✓
Application 3: L = {ww | w ∈ {0,1}*} is NOT Regular
Language: Strings that are a word repeated twice
Examples: ε, 00, 11, 0101, 1010, 001001, ...
Proof:
- Assume L is regular with pumping length n
- Choose w = 0n10n1 (w = (0n1)(0n1), so w ∈ L)
- By Pumping Lemma, w = xyz where |y| > 0 and |xy| ≤ n
- Since |xy| ≤ n, y consists only of 0's from first part
- Pump with i = 2: xy2z adds more 0's to first occurrence
- First part: 0n+k1 (where k = |y| > 0)
- Second part: 0n1 (unchanged)
- Not of form ww anymore!
- Contradiction! Therefore L is NOT regular ✓
Application 4: L = {0n1m | n ≠ m} is NOT Regular
Language: Strings with unequal number of 0's and 1's
Proof (using closure properties):
- Assume L is regular
- Regular languages are closed under complement
- So L̄ = {0n1m | n = m} ∪ {strings not of form 0*1*} would be regular
- Regular languages are closed under intersection with regular languages
- L̄ ∩ 0*1* = {0n1n | n ≥ 0} would be regular
- But we proved {0n1n} is NOT regular!
- Contradiction! Therefore L is NOT regular ✓
Application 5: L = {0i1j | i > j} is NOT Regular
Language: More 0's than 1's
Proof:
- Assume L is regular with pumping length n
- Choose w = 0n+11n ∈ L (n+1 > n)
- By Pumping Lemma, w = xyz where |xy| ≤ n, |y| > 0
- So y = 0k for some k > 0
- Pump with i = 0: xz = 0n+1-k1n
- If k = 1: we get 0n1n where n = n, not i > j!
- If k > 1: we get 0n+1-k1n where n+1-k ≤ n
- Either way, xz ∉ L
- Contradiction! Therefore L is NOT regular ✓
Common Non-Regular Languages (Using Pumping Lemma):
| Language | Description | Why Not Regular |
|---|---|---|
| {0n1n} | Equal 0's and 1's | Need to count and match |
| {ww} | Repeated string | Need to remember first half |
| {w wR} | Palindromes | Need to match forward and backward |
| {ap} | Prime length | Need to check primality |
| {an²} | Perfect squares | Need arithmetic computation |
| {anbncn} | Three-way equality | Need to count three types |
Key Applications Summary:
- Proving Non-Regularity: Main use - show languages require more than finite memory
- Understanding Limitations: Shows what DFA/NFA/Regex cannot do
- Theoretical Foundation: Separates regular from context-free languages
- Compiler Design: Determines when to use lexer vs parser
- Algorithm Analysis: Indicates when more powerful models needed
Important Reminder:
Pumping Lemma CANNOT prove a language IS regular!
- It's only a necessary condition, not sufficient
- Some non-regular languages satisfy pumping lemma
- To prove regularity: construct DFA/NFA/regex or use closure properties
Q4. Explain Context Free Grammar, Regular Grammar and Derivation Grammar
Answer:
1. Context-Free Grammar (CFG):
Definition:
A Context-Free Grammar is a 4-tuple G = (V, T, P, S) where:
- V: Finite set of variables (non-terminals) - usually uppercase letters
- T: Finite set of terminals (alphabet symbols) - usually lowercase letters
- P: Finite set of production rules of the form A → α where:
- A ∈ V (single variable on left side)
- α ∈ (V ∪ T)* (string of variables and terminals on right side)
- S ∈ V: Start symbol
Key Features of CFG:
- "Context-Free" means: Variable A can be replaced by α regardless of context (symbols around A don't matter)
- More powerful than regular grammars - can handle nested structures
- Left side has EXACTLY ONE variable
- Right side can have any combination of variables and terminals
- Can generate Context-Free Languages (CFL)
Example 1: Balanced Parentheses
S → ε
S → (S)
S → SS
Generates: ε, (), (()), ()(), ((())), (())(), ()(()), ...
Derivation of "(()())":
S ⇒ (S) [Apply S → (S)]
⇒ (SS) [Apply S → SS]
⇒ ((S)S) [Apply first S → (S)]
⇒ ((S)(S)) [Apply second S → (S)]
⇒ (()()) [Apply both S → ε]
Example 2: Arithmetic Expressions
E → E + E
E → E * E
E → (E)
E → id
Generates: id, id+id, id*id, (id+id)*id, ...
Note: This grammar is ambiguous (multiple parse trees possible)
Example 3: {0n1n | n ≥ 0}
S → 0S1
S → ε
Derivations:
- n=0: S ⇒ ε
- n=1: S ⇒ 0S1 ⇒ 01
- n=2: S ⇒ 0S1 ⇒ 00S11 ⇒ 0011
- n=3: S ⇒ 0S1 ⇒ 00S11 ⇒ 000S111 ⇒ 000111
This language is NOT regular but IS context-free!
2. Regular Grammar:
A Regular Grammar is a restricted form of CFG that generates exactly the Regular Languages.
Types of Regular Grammars:
Right-Linear Grammar: All productions of the form:
- A → wB (terminal string followed by ONE variable)
- A → w (terminal string only)
Where A, B ∈ V and w ∈ T*
Left-Linear Grammar: All productions of the form:
- A → Bw (ONE variable followed by terminal string)
- A → w (terminal string only)
Restrictions in Regular Grammar:
- At most ONE variable on right side
- If variable present, must be at END (right-linear) or START (left-linear)
- Cannot mix right-linear and left-linear in same grammar
- No recursion in the middle
Example 1: Right-Linear Grammar
Language: Strings ending with 'ab'
S → aS | bS | aB
B → b
Analysis:
- S → aS or bS: Read any symbol, stay in S
- S → aB: Read 'a', prepare for final 'b'
- B → b: Generate final 'b'
Generates: ab, aab, bab, aaab, abab, ababab, ...
Example 2: Left-Linear Grammar
Language: (ab)*
S → Sab | ε
Generates: ε, ab, abab, ababab, ...
Example 3: Binary Strings with Even 0's
S → 1S | 0A | ε
A → 1A | 0S
Analysis:
- S: even number of 0's seen
- A: odd number of 0's seen
- Reading 1 doesn't change state
- Reading 0 toggles between S and A
Comparison: Regular vs Context-Free Grammar:
| Feature | Regular Grammar | Context-Free Grammar |
|---|---|---|
| Production form | A → wB or A → w (restricted) |
A → α (any string) |
| Variables on right | At most ONE, at end/start | Any number, anywhere |
| Recursion | Only tail/head recursion | Any recursion (including nested) |
| Example production | S → aB ✓ S → ABc ✗ |
S → aB ✓ S → ABc ✓ |
| Languages generated | Regular Languages | Context-Free Languages |
| Can describe | Patterns without counting | Nested structures, counting |
| Example | (01)* ✓ 0ⁿ1ⁿ ✗ |
(01)* ✓ 0ⁿ1ⁿ ✓ |
| Automaton | Finite Automata | Pushdown Automata |
3. Derivation in Grammar:
A derivation is a sequence of production rule applications that transforms the start symbol into a terminal string.
Types of Derivations:
1. Leftmost Derivation:
Always replace the leftmost variable in each step.
Example Grammar:
E → E + T | T
T → T * F | F
F → (E) | id
Leftmost derivation of "id + id * id":
E ⇒ E + T [Replace leftmost E]
⇒ T + T [Replace leftmost E]
⇒ F + T [Replace leftmost T]
⇒ id + T [Replace leftmost F]
⇒ id + T * F [Replace leftmost T]
⇒ id + F * F [Replace leftmost T]
⇒ id + id * F [Replace leftmost F]
⇒ id + id * id [Replace leftmost F]
2. Rightmost Derivation:
Always replace the rightmost variable in each step.
Rightmost derivation of "id + id * id":
E ⇒ E + T [Replace rightmost E]
⇒ E + T * F [Replace rightmost T]
⇒ E + T * id [Replace rightmost F]
⇒ E + F * id [Replace rightmost T]
⇒ E + id * id [Replace rightmost F]
⇒ T + id * id [Replace rightmost E]
⇒ F + id * id [Replace rightmost T]
⇒ id + id * id [Replace rightmost F]
Derivation Notation:
- ⇒: Derives in one step (one production application)
- ⇒*: Derives in zero or more steps
- ⇒⁺: Derives in one or more steps
- ⇒lm: Leftmost derivation
- ⇒rm: Rightmost derivation
Parse Tree:
A parse tree (or derivation tree) is a graphical representation of a derivation.
Parse Tree for "id + id":
E
/|\
/ | \
E + T
| |
T F
| |
F id
|
id
Properties:
- Root: Start symbol (E)
- Internal nodes: Variables
- Leaves: Terminals
- Reading leaves left-to-right gives the derived string
- Same parse tree for both leftmost and rightmost derivations!
Language Generated by Grammar:
L(G) = {w ∈ T* | S ⇒* w}
The language consists of all terminal strings that can be derived from start symbol.
Important Concepts:
- Sentential Form: Any string derivable from S (can contain variables and terminals)
- Sentence: Sentential form containing only terminals (w ∈ T*)
- Ambiguity: Grammar is ambiguous if some string has multiple parse trees
- Equivalence: Two grammars are equivalent if they generate same language
Example: Ambiguous Grammar
E → E + E | E * E | id
String "id + id * id" has TWO parse trees:
Tree 1: (id + id) * id [add first]
Tree 2: id + (id * id) [multiply first]
This is ambiguous! Need to rewrite with precedence levels.
Applications:
- Programming Languages: Syntax specification
- Compilers: Parsing source code
- Natural Language Processing: Sentence structure
- XML/HTML: Document structure
- Formal Verification: Protocol specification
Q5. Explain the Chomsky Normal Form and Greibach Normal Form
Answer:
Normal forms are standardized formats for Context-Free Grammars that simplify analysis and implementation while preserving the language generated.
1. Chomsky Normal Form (CNF):
Definition:
A Context-Free Grammar is in Chomsky Normal Form if every production is in one of these forms:
- A → BC: Variable derives exactly TWO variables
- A → a: Variable derives single terminal
- S → ε: Start symbol can derive empty string (only if ε ∈ L)
Restrictions:
- If S → ε exists, S cannot appear on right side of any production
- No ε-productions except possibly S → ε
- No unit productions (A → B)
Why Chomsky Normal Form?
- Standard Format: Every CFG can be converted to CNF
- Binary Tree: Parse trees become binary trees
- Parsing: Enables efficient parsing algorithms (CYK algorithm)
- Complexity Analysis: Easy to prove bounds on derivation length
- Theorem Proving: Simplifies proofs about CFGs
Properties of CNF:
- For string of length n, derivation has exactly 2n-1 steps
- Parse tree height ≥ log₂(n)
- Every non-ε CFL has CNF grammar
Example 1: Simple CNF Grammar
S → AB
S → BC
A → BA
A → a
B → CC
B → b
C → AB
C → a
✓ All productions are either A → BC or A → a form
Converting to Chomsky Normal Form:
Step-by-step algorithm:
Step 1: Add New Start Symbol
Create new start S₀ → S to ensure start doesn't appear on right side
Original: S → ASA | aB
Add: S₀ → S
Step 2: Eliminate ε-Productions
Remove all A → ε (except possibly S → ε)
Original:
S → ASA | aB
A → B | ε
B → b | ε
After eliminating ε:
S → ASA | SA | AS | S | aB | a
A → B
B → b
Step 3: Eliminate Unit Productions
Remove all A → B (single variable productions)
Before: A → B, B → b
After: A → b (substitute)
Result:
S → ASA | SA | AS | S | aB | a
A → b
B → b
Step 4: Replace Terminals in Long Productions
For productions with terminals mixed with variables, create new variables for terminals
S → ASA becomes S → A₁SA₁ with A₁ → a
S → aB becomes S → A₁B with A₁ → a
After:
S → A₁SA₁ | SA | AS | A₁B
A₁ → a
A → b
B → b
Step 5: Break Long Productions
Productions with >2 variables broken into binary productions
S → A₁SA₁ (3 variables) breaks into:
S → A₁C₁
C₁ → SA₁
Final CNF:
S → A₁C₁ | SA | AS | A₁B
C₁ → SA₁
A₁ → a
A → b
B → b
Complete Example: Convert to CNF
Original Grammar:
S → ASA | aB
A → B | S
B → b | ε
Step 1: New start
S₀ → S
S → ASA | aB
A → B | S
B → b | ε
Step 2: Eliminate ε (B → ε makes B nullable)
S₀ → S
S → ASA | aB | a
A → B | S
B → b
Step 3: Eliminate unit productions
S₀ → ASA | aB | a
S → ASA | aB | a
A → b | ASA | aB | a
B → b
Step 4: Replace terminals
T_a → a
T_b → b
S₀ → ASA | T_aB | a
S → ASA | T_aB | a
A → b | ASA | T_aB | a
B → b
Step 5: Break long productions (ASA has 3 symbols)
S₀ → AC₁ | T_aB | a
S → AC₁ | T_aB | a
C₁ → SA
A → b | AC₁ | T_aB | a
B → b
T_a → a
Final CNF ✓
2. Greibach Normal Form (GNF):
Definition:
A Context-Free Grammar is in Greibach Normal Form if every production is in the form:
A → aα
Where:
- a ∈ T: Terminal symbol (MUST be first)
- α ∈ V*: String of zero or more variables
Exception: S → ε allowed if ε ∈ L(G)
Why Greibach Normal Form?
- Direct Terminal Generation: Every step produces exactly one terminal
- Predictable Derivation: For string of length n, exactly n derivation steps
- PDA Construction: Direct conversion to Pushdown Automata
- Leftmost Derivation: Easy to construct leftmost derivations
Properties of GNF:
- Derivation length = String length (one terminal per step)
- No left recursion
- Every non-ε CFL has GNF grammar
- One-to-one mapping with PDA transitions
Example 1: Simple GNF Grammar
S → aAB | bB | a
A → aA | bB | a
B → bB | b
✓ Every production starts with terminal
✓ Followed by zero or more variables
Derivation of "aba":
S ⇒ aAB [Produce 'a']
⇒ abB [Produce 'b']
⇒ aba [Produce 'a']
Exactly 3 steps for 3 terminals!
Example 2: L = {0ⁿ1ⁿ | n ≥ 1} in GNF
S → 0S1 | 01
Wait, this is NOT in GNF! (has terminal at end)
Correct GNF:
S → 0A
A → 0A1 | 01
Or better:
S → 0SA₁ | 0A₁
A₁ → 1
Now every production starts with terminal ✓
Converting to Greibach Normal Form:
More complex than CNF conversion:
- Convert to CNF first
- Eliminate left recursion
- Ensure every production starts with terminal
- May require introducing many new variables
Example: Eliminate Left Recursion
Original (has left recursion):
A → Aα | β (where β doesn't start with A)
Converted (no left recursion):
A → βA'
A' → αA' | ε
For GNF, further transform to start with terminal
Comparison: CNF vs GNF:
| Feature | Chomsky Normal Form | Greibach Normal Form |
|---|---|---|
| Production form | A → BC or A → a | A → aα (α is variables) |
| Number of symbols | Exactly 1 or 2 | 1 terminal + any number of variables |
| Terminal position | Alone or generated last | Always FIRST |
| Parse tree | Binary tree | Terminal at every level |
| Derivation steps | 2n-1 for string of length n | Exactly n for string of length n |
| Left recursion | Allowed | Not allowed |
| Conversion ease | Easier to convert to | More complex conversion |
| Main use | Parsing (CYK algorithm) | PDA construction |
| Example | S → AB, A → a | S → aAB, A → a |
Applications:
- CNF: CYK parsing algorithm, complexity analysis, proving language properties
- GNF: Direct PDA construction, top-down parsing, compiler design
Important Theorem:
Every Context-Free Language (except possibly empty string) can be generated by:
- A grammar in Chomsky Normal Form
- A grammar in Greibach Normal Form
Both normal forms have same expressive power as general CFGs!
Q6. What is Push Down Automata and Also Explain DPDA
Answer:
Pushdown Automata (PDA):
A Pushdown Automaton is a finite automaton with an additional stack memory. It's the computational model for Context-Free Languages.
Formal Definition:
A PDA is a 7-tuple P = (Q, Σ, Γ, δ, q₀, Z₀, F) where:
- Q: Finite set of states
- Σ: Input alphabet
- Γ: Stack alphabet
- δ: Q × (Σ ∪ {ε}) × Γ → P(Q × Γ*): Transition function
- δ(q, a, X) = {(p₁, γ₁), (p₂, γ₂), ...}
- From state q, reading a, with X on stack top
- Can go to state pᵢ and replace X with γᵢ
- q₀ ∈ Q: Initial state
- Z₀ ∈ Γ: Initial stack symbol
- F ⊆ Q: Final states (for acceptance by final state)
Components of PDA:
- Input Tape: Contains input string, read-only, left-to-right
- Finite Control: Maintains current state
- Stack: Unlimited LIFO memory
- Can push symbols onto stack
- Can pop symbols from stack
- Can read top symbol without popping
How PDA Works:
In state q, reading input a, with X on stack top:
1. Pop X from stack
2. Based on δ(q, a, X), choose transition (p, γ)
3. Go to state p
4. Push string γ onto stack (rightmost symbol on top)
5. Move to next input (if a ≠ ε)
Acceptance Methods:
- Acceptance by Final State:
- Input accepted if PDA reaches final state after reading entire input
- Stack can be non-empty
- Acceptance by Empty Stack:
- Input accepted if stack becomes empty after reading entire input
- No final states needed
Important: Both acceptance methods are equivalent in power - can convert between them!
Example 1: PDA for L = {0ⁿ1ⁿ | n ≥ 1}
Idea: Push all 0's onto stack, pop one for each 1
PDA Design:
States: {q₀, q₁, q₂}
Stack Alphabet: {0, Z₀}
Transitions:
| State | Input | Stack Top | Next State | Stack Action |
|---|---|---|---|---|
| q₀ | 0 | Z₀ | q₀ | Push 0 (0Z₀) |
| q₀ | 0 | 0 | q₀ | Push 0 (00) |
| q₀ | 1 | 0 | q₁ | Pop 0 (ε) |
| q₁ | 1 | 0 | q₁ | Pop 0 (ε) |
| q₁ | ε | Z₀ | q₂ | Pop Z₀ (ε) |
Trace for "0011":
(q₀, 0011, Z₀) [Start]
⊢ (q₀, 011, 0Z₀) [Push 0]
⊢ (q₀, 11, 00Z₀) [Push 0]
⊢ (q₁, 1, 0Z₀) [Pop 0]
⊢ (q₁, ε, Z₀) [Pop 0]
⊢ (q₂, ε, ε) [Accept - reached final state]
Example 2: PDA for Balanced Parentheses
Language: Well-formed parentheses
Transitions:
- δ(q, '(', Z₀) = {(q, (Z₀)} - Push ( on empty stack
- δ(q, '(', '(') = {(q, (()} - Push ( on stack
- δ(q, ')', '(') = {(q, ε)} - Pop ( when seeing )
- δ(q, ε, Z₀) = {(f, Z₀)} - Accept if stack has only Z₀
Examples:
- "(())" ✓ - Balanced
- "()()" ✓ - Balanced
- "(()" ✗ - Too many open
- "())" ✗ - Too many close
Power of PDA:
- More powerful than FA: Can recognize {0ⁿ1ⁿ}
- Equivalent to CFG: L recognized by PDA ⟺ L generated by CFG
- Less powerful than TM: Cannot recognize {0ⁿ1ⁿ2ⁿ}
Deterministic Pushdown Automata (DPDA):
Definition of DPDA:
A PDA is deterministic if it satisfies:
- At most one transition: For every (q, a, X), |δ(q, a, X)| ≤ 1
- No ε-ambiguity: If δ(q, ε, X) is defined, then δ(q, a, X) must be undefined for all a ∈ Σ
In other words: No choice in transitions!
Key Differences: DPDA vs NPDA:
| Feature | DPDA (Deterministic) | NPDA (Nondeterministic) |
|---|---|---|
| Transitions | At most one choice | Multiple choices allowed |
| Behavior | Predictable path | Can explore multiple paths |
| ε-transitions | Restricted (no ambiguity) | Unrestricted |
| Languages | Deterministic CFL (DCFL) | All CFL |
| Power | LESS powerful | MORE powerful |
| Closure under complement | YES (closed) | NO (not closed) |
| Examples | {0ⁿ1ⁿ}, LR(k) languages | {wwᴿ}, all CFL |
| Real-world | Programming language parsers | Theoretical model |
Example: DPDA for {0ⁿ1ⁿ | n ≥ 1}
δ(q₀, 0, Z₀) = (q₀, 0Z₀) ✓ Only one choice
δ(q₀, 0, 0) = (q₀, 00) ✓ Only one choice
δ(q₀, 1, 0) = (q₁, ε) ✓ Only one choice
δ(q₁, 1, 0) = (q₁, ε) ✓ Only one choice
δ(q₁, ε, Z₀) = (q₂, Z₀) ✓ Only one ε-transition
and no input transition
from (q₁, Z₀)
This is DETERMINISTIC ✓
Languages NOT Recognized by DPDA:
L = {wwᴿ | w ∈ {a,b}*} (Even Palindromes)
Problem: DPDA cannot determine the middle point!
- NPDA can nondeterministically guess middle
- DPDA has no way to know when to switch from pushing to popping
- Example: "abba" - when to stop pushing and start popping?
Conclusion: {wwᴿ} is CFL but NOT DCFL
DCFL ⊂ CFL (Proper Subset):
- Every DCFL is CFL (DPDA is special case of NPDA)
- Not every CFL is DCFL ({wwᴿ} is counterexample)
- Therefore: DCFL ⊂ CFL (proper subset)
Applications:
- NPDA: Theoretical model, proving language properties
- DPDA: Practical parsing (LR parsers, compiler design)
- Programming Languages: Most languages designed to be DCFL
- XML/HTML Parsing: Deterministic parsing
Important Results:
- PDA (by final state) ≡ PDA (by empty stack)
- PDA ≡ CFG (same expressive power)
- DPDA ≠ NPDA (DPDA less powerful)
- DCFL is closed under complement (CFL is not)
Q7. What is Turing Machine. Explain in Detail
Answer:
A Turing Machine (TM) is the most powerful computational model in automata theory. It was proposed by Alan Turing in 1936 as a mathematical model of computation that defines an abstract machine.
Formal Definition:
A Turing Machine is a 7-tuple M = (Q, Σ, Γ, δ, q₀, B, F) where:
- Q: Finite set of states
- Σ: Input alphabet (symbols that can appear in input)
- Γ: Tape alphabet where Σ ⊂ Γ (all symbols that can appear on tape)
- δ: Q × Γ → Q × Γ × {L, R}: Transition function
- δ(q, X) = (p, Y, D)
- In state q, reading X, go to state p, write Y, move Direction D
- q₀ ∈ Q: Initial/Start state
- B ∈ Γ: Blank symbol (B ∉ Σ)
- F ⊆ Q: Set of final/accepting states
Components of Turing Machine:
- Infinite Tape:
- Divided into cells, each holding one symbol from Γ
- Infinite in both directions
- Initially contains input string, rest is blank (B)
- Tape Head:
- Points to one cell on tape
- Can read and write symbols
- Can move LEFT or RIGHT one cell at a time
- Finite Control:
- Has finite number of states
- Controls behavior based on current state and tape symbol
How Turing Machine Works:
At each step:
1. Read symbol X at current tape position
2. Based on current state q and symbol X:
- Change to new state p
- Write new symbol Y at current position
- Move head LEFT (L) or RIGHT (R)
3. Repeat until reaching accepting or rejecting state
Visual Representation:
Finite Control
+----------+
| State: q |
+----------+
↓
... B | 0 | 1 | 0 | B | B ...
↑
Tape Head
(currently at position with '1')
Instantaneous Description (ID):
Configuration of TM at any moment: X₁X₂...qXᵢXᵢ₊₁...Xₙ
- q is current state
- Xᵢ is symbol under tape head
- X₁...Xᵢ₋₁ are symbols to the left
- Xᵢ₊₁...Xₙ are symbols to the right
Moves of TM:
Notation: ID₁ ⊢ ID₂ (ID₁ yields ID₂ in one move)
Example:
If δ(q, X) = (p, Y, R) then:
X₁X₂...qXXᵢ₊₁...Xₙ ⊢ X₁X₂...YpXᵢ₊₁...Xₙ
(Replace X with Y, move right to state p)
If δ(q, X) = (p, Y, L) then:
X₁X₂...Xᵢ₋₁qXXᵢ₊₁...Xₙ ⊢ X₁X₂...pXᵢ₋₁YXᵢ₊₁...Xₙ
(Replace X with Y, move left to state p)
Acceptance/Rejection:
- Acceptance by Final State:
- TM accepts if it enters a final state (q ∈ F)
- Input completely processed or not doesn't matter
- Acceptance by Halting:
- TM accepts if it halts (no move defined)
- TM rejects if it enters infinite loop
Example 1: TM for L = {0ⁿ1ⁿ | n ≥ 1}
Idea: Match each 0 with corresponding 1
Algorithm:
- Replace leftmost 0 with X
- Move right past all 0's and 1's
- Replace leftmost 1 with Y
- Move left back to start
- Repeat until all 0's matched with 1's
- Accept if tape has only X's and Y's
States:
- q₀: Start state
- q₁: After replacing 0 with X, searching for 1
- q₂: After replacing 1 with Y, going back
- q₃: Checking if done
- q₄: Accept state
Transition Table:
| Current State | Read Symbol | Next State | Write Symbol | Direction |
|---|---|---|---|---|
| q₀ | 0 | q₁ | X | R |
| q₀ | Y | q₃ | Y | R |
| q₁ | 0 | q₁ | 0 | R |
| q₁ | Y | q₁ | Y | R |
| q₁ | 1 | q₂ | Y | L |
| q₂ | 0 | q₂ | 0 | L |
| q₂ | Y | q₂ | Y | L |
| q₂ | X | q₀ | X | R |
| q₃ | Y | q₃ | Y | R |
| q₃ | B | q₄ | B | R |
Trace for input "0011":
1. q₀0011B [Start]
2. Xq₁011B [Replace 0 with X, move right]
3. X0q₁11B [Skip 0]
4. X0q₂Y1B [Replace 1 with Y, move left]
5. Xq₂0Y1B [Move left]
6. q₂X0Y1B [Move left]
7. Xq₀0Y1B [Back at X, move right]
8. XXq₁Y1B [Replace 0 with X, move right]
9. XXYq₁1B [Skip Y]
10. XXq₂YYB [Replace 1 with Y, move left]
11. Xq₂XYYB [Move left]
12. XXq₀YYB [Back at X, move right]
13. XXYq₃YB [No more 0's, check]
14. XXYYq₃B [Move right]
15. XXYYBq₄ [Accept! ✓]
Example 2: TM for Addition
Language: Binary addition (compute m + n)
Input: 0ᵐ10ⁿ (m and n in unary)
Output: 0ᵐ⁺ⁿ
Algorithm:
- Replace the separator '1' with '0'
- Erase the rightmost '0'
Example: 000100 → 000000 → 00000 (3+2=5)
Types of Turing Machines:
| Type | Description | Power |
|---|---|---|
| Single-tape TM | One tape (basic model) | Universal |
| Multi-tape TM | Multiple tapes with separate heads | Same as single-tape |
| Non-deterministic TM | Multiple transitions possible | Same as deterministic |
| Universal TM | Can simulate any other TM | Universal computation |
Church-Turing Thesis:
Thesis: Any function that is "effectively computable" can be computed by a Turing Machine.
Meaning: TM captures the essence of what it means to compute!
- All reasonable computational models equivalent to TM
- Modern computers = Turing Machines (with finite memory)
- If TM can't solve it, no algorithm can
Languages Recognized by TM:
- Recursively Enumerable (RE):
- L is RE if some TM accepts all strings in L
- TM may loop forever on strings not in L
- Semi-decidable
- Recursive:
- L is recursive if some TM accepts L and halts on all inputs
- TM always halts (accept or reject)
- Decidable
- Recursive ⊂ RE (proper subset)
Power Comparison:
| Machine | Memory | Languages |
|---|---|---|
| Finite Automata | None (only states) | Regular Languages |
| Pushdown Automata | Stack (LIFO) | Context-Free Languages |
| Turing Machine | Infinite Tape | Recursively Enumerable |
Applications and Significance:
- Foundation of Computer Science: Defines limits of computation
- Complexity Theory: Basis for P, NP, etc.
- Undecidability: Proves some problems have no algorithm (Halting Problem)
- Programming Languages: All modern languages equivalent to TM
- AI and Computation: Understanding what machines can/cannot do
Important Facts:
- TM is the MOST POWERFUL computational model
- Deterministic TM = Nondeterministic TM (same power)
- Multi-tape TM = Single-tape TM (same power)
- Every modern computer is a TM with finite tape
- Halting Problem is undecidable (TM cannot solve it for all TMs)
Q8. Explain the P, NP, NP-Complete, and NP-Hard Problems
Answer:
Computational complexity theory classifies problems based on the computational resources (time, space) required to solve them. The P, NP, NP-Complete, and NP-Hard classes form the foundation of this classification.
1. P (Polynomial Time):
Definition:
P is the class of decision problems that can be solved by a deterministic Turing Machine in polynomial time.
Formally: P = {L | L can be decided in O(nᵏ) time for some constant k}
- Solution algorithm runs in O(nᵏ) time
- Efficient, tractable problems
- Practically solvable
Characteristics of P:
- Deterministic: One computational path
- Efficient: Polynomial time means feasible for large inputs
- Closed under: Union, intersection, complement, concatenation
- Decidable: Always halts with answer
Examples of P Problems:
| Problem | Time Complexity |
|---|---|
| Sorting | O(n log n) |
| Binary Search | O(log n) |
| Graph Connectivity | O(V + E) |
| Shortest Path (Dijkstra) | O(V²) or O(E log V) |
| Minimum Spanning Tree | O(E log V) |
| Primality Testing (AKS) | O((log n)¹²) |
| Matrix Multiplication | O(n²·³⁷³) |
2. NP (Nondeterministic Polynomial Time):
Definition:
NP is the class of decision problems where a "yes" answer can be verified in polynomial time.
Two equivalent definitions:
- Nondeterministic TM: Can be solved in polynomial time by non-deterministic TM
- Verifier-based: Given solution (certificate), can verify it in polynomial time
Characteristics of NP:
- Verification: Easy to check solution, hard to find it
- Certificate: Needs "proof" or "witness" that can be verified quickly
- Relationship: P ⊆ NP (if you can solve in poly time, you can verify in poly time)
- Unknown: Whether P = NP is biggest open problem in CS!
Examples of NP Problems:
| Problem | Verification |
|---|---|
| Hamiltonian Cycle | Given a cycle, check if it visits all vertices once - O(n) |
| Traveling Salesman | Given a tour, check if total distance ≤ k - O(n) |
| 3-SAT | Given assignment, check if formula satisfied - O(n) |
| Vertex Cover | Given set of k vertices, check if covers all edges - O(E) |
| Subset Sum | Given subset, check if sum = target - O(n) |
Note: All these problems have exponential time solutions but polynomial time verification!
3. NP-Complete:
Definition:
A problem L is NP-Complete if:
- L ∈ NP: L is in NP (can verify solution in poly time)
- L is NP-Hard: Every problem in NP can be reduced to L in polynomial time
Meaning: NP-Complete problems are the "hardest" problems in NP!
Significance of NP-Complete:
- If ANY NP-Complete problem can be solved in polynomial time, then P = NP
- If ANY NP-Complete problem cannot be solved in polynomial time, then P ≠ NP
- All NP-Complete problems are "equally hard"
- Can reduce any NP-Complete problem to any other in poly time
Proving NP-Completeness:
To prove problem X is NP-Complete:
- Show X ∈ NP: Give polynomial-time verification algorithm
- Show X is NP-Hard: Reduce known NP-Complete problem to X in polynomial time
Common NP-Complete Problems:
| Problem | Description |
|---|---|
| SAT | Boolean satisfiability (first proven NP-Complete - Cook-Levin 1971) |
| 3-SAT | SAT with clauses of exactly 3 literals |
| Hamiltonian Cycle | Does graph have cycle visiting each vertex once? |
| TSP (decision) | Is there tour of length ≤ k? |
| Vertex Cover | Can k vertices cover all edges? |
| Clique | Is there complete subgraph of size k? |
| Graph Coloring | Can graph be colored with k colors? |
| Subset Sum | Does subset sum to target? |
| Knapsack (decision) | Can value ≥ V be achieved with weight ≤ W? |
4. NP-Hard:
Definition:
A problem L is NP-Hard if:
Every problem in NP can be reduced to L in polynomial time.
Important: L does NOT need to be in NP!
- At least as hard as hardest problems in NP
- May not even be decision problems
- May not be in NP (could be even harder!)
NP-Hard vs NP-Complete:
- NP-Complete = NP ∩ NP-Hard
- NP-Hard problems may be harder than NP (not verifiable in poly time)
- Optimization versions of NP-Complete problems are often NP-Hard but not NP-Complete
Examples of NP-Hard (but not NP-Complete):
| Problem | Why NP-Hard but not NP-Complete? |
|---|---|
| TSP (optimization) | Find shortest tour (not decision problem) |
| Halting Problem | Undecidable (not even in NP) |
| General Game Playing | Harder than NP |
| Knapsack (optimization) | Maximize value (not decision problem) |
Complexity Class Hierarchy:
Undecidable Problems
↑
NP-Hard Problems
↑
NP-Complete Problems
↗ ↖
NP ?
↑ ?
P ?
P ⊆ NP (proven)
P = NP? (unknown - million dollar question!)
NP-Complete ⊆ NP-Hard
NP-Complete = NP ∩ NP-Hard
Visual Relationship:
┌─────────────────────────────────────┐
│ NP-Hard │
│ ┌──────────────────────────────┐ │
│ │ NP │ │
│ │ ┌─────────────────────┐ │ │
│ │ │ NP-Complete │ │ │
│ │ │ (Hardest in NP) │ │ │
│ │ └─────────────────────┘ │ │
│ │ ┌──────────┐ │ │
│ │ │ P │ │ │
│ │ │ (Easy) │ │ │
│ │ └──────────┘ │ │
│ └──────────────────────────────┘ │
│ Optimization TSP, etc. │
└─────────────────────────────────────┘
The P vs NP Question:
The Million Dollar Question:
Does P = NP?
If P = NP:
- Every problem with poly-time verifiable solution has poly-time solving algorithm
- Would revolutionize cryptography (most encryption breakable!)
- Many practical problems become efficiently solvable
If P ≠ NP: (most believe this)
- Some problems inherently harder than others
- Cryptography remains secure
- NP-Complete problems have no efficient solution
Prize: $1,000,000 (Clay Mathematics Institute Millennium Prize)
Practical Implications:
| Class | Approach |
|---|---|
| P | Solve optimally with exact algorithm |
| NP-Complete | Use approximation algorithms, heuristics, or solve small instances |
| NP-Hard | Same as NP-Complete, possibly harder |
Summary:
- P: Efficiently solvable
- NP: Efficiently verifiable
- NP-Complete: Hardest problems in NP
- NP-Hard: At least as hard as NP-Complete
- P ⊆ NP ⊆ NP-Hard
- NP-Complete = NP ∩ NP-Hard
Q9. Explain the Hamiltonian Problem with Example
Answer:
The Hamiltonian Path/Cycle Problem is a classic problem in graph theory and one of the most well-known NP-Complete problems in computer science.
Definitions:
Hamiltonian Path:
A path in a graph that visits each vertex exactly once.
- Starts at one vertex, ends at another
- Never repeats a vertex
- May or may not use all edges
Hamiltonian Cycle (or Circuit):
A cycle in a graph that visits each vertex exactly once and returns to starting vertex.
- Closed path (cycle)
- Visits every vertex exactly once
- Returns to starting vertex
Formal Problem Statement:
Decision Problem: Given a graph G = (V, E), does there exist a Hamiltonian path/cycle in G?
- Input: Graph G with n vertices
- Output: YES if Hamiltonian path/cycle exists, NO otherwise
- Complexity: NP-Complete
Example 1: Graph WITH Hamiltonian Cycle
Graph:
A ---- B
| |
| |
D ---- C
Edges: {(A,B), (B,C), (C,D), (D,A)}
Hamiltonian Cycle: A → B → C → D → A ✓
- Visits all 4 vertices exactly once
- Returns to starting vertex A
- This is a Hamiltonian Cycle!
Other Hamiltonian Cycles:
B → C → D → A → B
C → D → A → B → C
D → A → B → C → D
(All are rotations/reflections of same cycle)
Example 2: Graph WITHOUT Hamiltonian Cycle
Graph:
A ---- B ---- C
| |
| |
D ----------- E
Edges: {(A,B), (B,C), (C,E), (E,D), (D,A)}
Try all possible paths starting from A:
A → B → C → E → D → ? (need to return to A, but no edge from D to A)
A → D → E → C → B → ? (need to return to A, but no edge from B to A)
Problem: After visiting all vertices, cannot return to start!
Hamiltonian Cycle: DOES NOT EXIST ✗
However, Hamiltonian PATH exists:
B → A → D → E → C ✓ (visits all vertices once)
Example 3: Complete Graph K₅
Complete graph with 5 vertices (every vertex connected to every other):
A
/|\\\
/ | \\\
/ | \\\
B---+---C
\ | /
\ | /
\|/
D---E
Every pair of vertices connected!
Hamiltonian Cycle exists: A → B → C → D → E → A ✓
In fact, complete graph Kₙ (n ≥ 3) ALWAYS has Hamiltonian cycle!
Number of distinct Hamiltonian cycles in Kₙ: (n-1)!/2
For K₅: (5-1)!/2 = 24/2 = 12 distinct cycles
Example 4: Detailed Trace
Graph:
1 ---- 2
/| |\\
/ | | \\
/ | | \\
5 | | 3
\ | | /
\ | | /
\| |/
6 ---- 4
Edges: {(1,2), (1,5), (1,6), (2,3), (2,4), (3,4), (4,6), (5,6)}
Find Hamiltonian Cycle:
Try starting from vertex 1:
Attempt 1: 1 → 2 → 3 → 4 → 6 → 5 → ?
Need edge (5,1) but doesn't exist ✗
Attempt 2: 1 → 2 → 4 → 3 → ?
Stuck, can't reach remaining vertices ✗
Attempt 3: 1 → 2 → 4 → 6 → 5 → ?
Need edge (5,3) but doesn't exist ✗
Attempt 4: 1 → 5 → 6 → 4 → 3 → 2 → ?
Need edge (2,1) - YES, exists! ✓
Hamiltonian Cycle Found: 1 → 5 → 6 → 4 → 3 → 2 → 1 ✓
Properties and Characteristics:
| Property | Description |
|---|---|
| Complexity | NP-Complete (no known polynomial-time algorithm) |
| Related to | Traveling Salesman Problem |
| Graph types | Applies to directed/undirected graphs |
| Verification | Easy - check if path visits all vertices (O(n)) |
| Finding solution | Hard - may need to try exponential paths |
Necessary Conditions (Not Sufficient):
For Hamiltonian Cycle to exist:
- Degree: Every vertex must have degree ≥ 2
- Connectivity: Graph must be connected
- No Cut Vertex: Removing one vertex shouldn't disconnect graph (for some cases)
Note: These are necessary but NOT sufficient conditions!
Sufficient Conditions:
Dirac's Theorem (1952):
If G has n ≥ 3 vertices and every vertex has degree ≥ n/2, then G has Hamiltonian cycle.
Example: Graph with 6 vertices where each vertex has degree ≥ 3
Ore's Theorem (1960):
If G has n ≥ 3 vertices and for every pair of non-adjacent vertices u, v: deg(u) + deg(v) ≥ n, then G has Hamiltonian cycle.
Weaker condition than Dirac's theorem
Special Cases:
| Graph Type | Hamiltonian Cycle? |
|---|---|
| Complete Graph Kₙ (n ≥ 3) | Always YES |
| Cycle Cₙ | Always YES (the cycle itself) |
| Tree | Only if path (no cycles allowed) |
| Bipartite Graph | Only if both partitions have equal size |
| Petersen Graph | YES (but not planar Hamiltonian) |
Algorithms:
- Backtracking:
- Try all possible paths systematically
- Time: O(n!) - exponential
- Works for small graphs
- Dynamic Programming:
- Held-Karp algorithm
- Time: O(n²2ⁿ)
- Better than naive but still exponential
- Heuristics:
- Nearest neighbor, genetic algorithms
- No guarantee of finding solution
- Fast but may miss existing cycles
Backtracking Algorithm:
HamiltonianCycle(graph G, path, pos):
if pos == n: // All vertices included
if edge exists from path[pos-1] to path[0]:
return true // Cycle found!
else:
return false
for each vertex v in G:
if isSafe(v, graph, path, pos):
path[pos] = v
if HamiltonianCycle(G, path, pos+1):
return true
path[pos] = -1 // Backtrack
return false
isSafe(v, graph, path, pos):
// Check if vertex v can be added at position pos
if edge doesn't exist from path[pos-1] to v:
return false
if v already in path:
return false
return true
Applications:
- Route Planning: Visit all cities exactly once
- Puzzle Solving: Knight's tour on chessboard
- DNA Sequencing: Finding optimal sequence assembly
- Circuit Design: Testing all components
- Computer Graphics: Polygon vertex ordering
Relationship to TSP:
- Hamiltonian Cycle is special case of TSP
- TSP: Find shortest Hamiltonian cycle (optimization)
- Hamiltonian: Does ANY Hamiltonian cycle exist? (decision)
- Both are NP-Complete/NP-Hard
Important Facts:
- Finding Hamiltonian cycle is NP-Complete
- Verifying a cycle is Hamiltonian is O(n) - easy!
- No known polynomial-time algorithm
- For dense graphs (many edges), more likely to have Hamiltonian cycle
- First proven NP-Complete by Richard Karp (1972)
Q10. Explain Traveling Salesman Problem with Example
Answer:
The Traveling Salesman Problem (TSP) is one of the most famous and extensively studied problems in combinatorial optimization and computational complexity theory.
Problem Statement:
Informal Description:
A salesman must visit n cities exactly once each, then return to the starting city. What is the shortest possible route?
Formal Definition:
Given:
- Set of n cities
- Distance d(i,j) between every pair of cities i and j
Find: A tour (Hamiltonian cycle) that minimizes total distance traveled
Objective: Minimize Σ d(city_i, city_{i+1}) for all cities in tour
Two Versions:
| Version | Problem Type | Complexity |
|---|---|---|
| Decision TSP | Is there a tour with distance ≤ k? | NP-Complete |
| Optimization TSP | Find tour with minimum distance | NP-Hard (harder!) |
Example 1: Small TSP Instance (4 Cities)
Cities: A, B, C, D
Distance Matrix:
| A | B | C | D | |
|---|---|---|---|---|
| A | 0 | 10 | 15 | 20 |
| B | 10 | 0 | 35 | 25 |
| C | 15 | 35 | 0 | 30 |
| D | 20 | 25 | 30 | 0 |
All Possible Tours (starting from A):
Tour 1: A → B → C → D → A
Distance: 10 + 35 + 30 + 20 = 95
Tour 2: A → B → D → C → A
Distance: 10 + 25 + 30 + 15 = 80 ✓ BEST!
Tour 3: A → C → B → D → A
Distance: 15 + 35 + 25 + 20 = 95
Tour 4: A → C → D → B → A
Distance: 15 + 30 + 25 + 10 = 80 ✓ BEST!
Tour 5: A → D → B → C → A
Distance: 20 + 25 + 35 + 15 = 95
Tour 6: A → D → C → B → A
Distance: 20 + 30 + 35 + 10 = 95
Optimal Tour: A → B → D → C → A (or reverse)
Optimal Distance: 80
Note: For n=4 cities, there are (4-1)!/2 = 3 unique tours
Number of Possible Tours:
- For n cities: (n-1)!/2 unique tours
- n=4: 3 tours
- n=5: 12 tours
- n=10: 181,440 tours
- n=20: 60,822,550,204,416,000 tours!
- Grows factorially - exponential explosion!
Example 2: Geometric TSP (Cities on Plane)
Cities with (x,y) coordinates:
A = (0, 0)
B = (3, 0)
C = (3, 4)
D = (0, 4)
This forms a rectangle!
Calculate Euclidean distances:
d(A,B) = √[(3-0)² + (0-0)²] = 3
d(B,C) = √[(3-3)² + (4-0)²] = 4
d(C,D) = √[(0-3)² + (4-4)²] = 3
d(D,A) = √[(0-0)² + (4-0)²] = 4
d(A,C) = √[(3-0)² + (4-0)²] = 5
d(B,D) = √[(0-3)² + (4-0)²] = 5
Compare tours:
A → B → C → D → A: 3 + 4 + 3 + 4 = 14 ✓ OPTIMAL
A → B → D → C → A: 3 + 5 + 3 + 5 = 16
A → C → B → D → A: 5 + 4 + 5 + 4 = 18
Optimal: Follow rectangle perimeter = 14
Algorithms for TSP:
1. Exact Algorithms:
| Algorithm | Time Complexity | Description |
|---|---|---|
| Brute Force | O(n!) | Try all permutations |
| Dynamic Programming (Held-Karp) | O(n²2ⁿ) | Better but still exponential |
| Branch and Bound | O(n!) worst case | Prunes search space |
Brute Force Algorithm:
TSP_BruteForce(cities[], dist[][]):
min_distance = ∞
best_tour = null
for each permutation P of cities:
current_distance = 0
for i = 0 to n-1:
current_distance += dist[P[i]][P[(i+1) % n]]
if current_distance < min_distance:
min_distance = current_distance
best_tour = P
return (best_tour, min_distance)
Time Complexity: O(n!) - try all (n-1)! tours
Space: O(n)
Practical limit: ~15 cities
2. Approximation Algorithms:
Nearest Neighbor Heuristic:
Greedy approach: Always go to nearest unvisited city
NearestNeighbor(start_city):
current = start_city
visited = {start_city}
tour = [start_city]
total_distance = 0
while visited.size < n:
nearest = city with minimum dist[current][city]
where city not in visited
tour.append(nearest)
visited.add(nearest)
total_distance += dist[current][nearest]
current = nearest
total_distance += dist[current][start_city] // Return home
return (tour, total_distance)
Time Complexity: O(n²)
Approximation: No guarantee (can be arbitrarily bad!)
Example with 4 cities:
Start at A:
Nearest to A: B (distance 10)
Nearest to B: D (distance 25, C=35)
Nearest to D: C (distance 30, only unvisited)
Return to A: distance 15
Tour: A → B → D → C → A
Total: 10 + 25 + 30 + 15 = 80 ✓ (happens to be optimal!)
Note: Nearest neighbor doesn't always find optimal!
2-Approximation Algorithm (MST-based):
For metric TSP: Guarantees tour ≤ 2 × optimal
Algorithm:
1. Find Minimum Spanning Tree (MST) of cities
2. Do DFS traversal of MST (visits each edge twice)
3. Create shortcut tour by skipping repeated vertices
Guarantee: Tour length ≤ 2 × OPT
Time: O(n² log n) using Prim's algorithm
Why it works:
- MST cost ≤ OPT (removing one edge from optimal tour gives spanning tree)
- DFS traversal = 2 × MST cost
- Shortcuts only reduce distance (triangle inequality)
- Therefore: Final tour ≤ 2 × MST ≤ 2 × OPT
Christofides Algorithm (1.5-approximation):
Best known approximation for metric TSP
Algorithm:
1. Find MST of graph
2. Find vertices with odd degree in MST
3. Find minimum-weight perfect matching on odd-degree vertices
4. Combine MST and matching to form Eulerian graph
5. Find Eulerian tour
6. Convert to Hamiltonian tour by skipping repeated vertices
Guarantee: Tour length ≤ 1.5 × OPT
Time: O(n³)
This is the best known polynomial-time approximation!
Special Cases:
| TSP Variant | Constraint | Complexity |
|---|---|---|
| Euclidean TSP | Points in 2D plane with Euclidean distance | NP-Hard but admits PTAS |
| Metric TSP | Distances satisfy triangle inequality | NP-Hard, 1.5-approximation exists |
| Asymmetric TSP | d(i,j) ≠ d(j,i) | Generally harder |
| Bottleneck TSP | Minimize maximum edge in tour | Can be solved in O(n² log n) |
Applications:
- Logistics: Delivery route optimization (FedEx, Amazon)
- Manufacturing: PCB drilling, robot arm movement
- DNA Sequencing: Fragment assembly
- Astronomy: Telescope observation scheduling
- Microchip Production: X-ray crystallography
- Network Design: Laying fiber optic cables
Real-World Solutions:
- Concorde TSP Solver: Solved 85,900 city instance!
- LKH (Lin-Kernighan-Helsgaun): State-of-the-art heuristic
- Genetic Algorithms: Good for large instances
- Simulated Annealing: Escapes local optima
- Ant Colony Optimization: Nature-inspired approach
Comparison with Hamiltonian Cycle:
| Feature | Hamiltonian Cycle | TSP |
|---|---|---|
| Goal | Find ANY cycle visiting all vertices | Find SHORTEST such cycle |
| Type | Decision problem | Optimization problem |
| Complexity | NP-Complete | NP-Hard |
| Distances | Not considered | Central to problem |
| Approximation | N/A (yes/no answer) | Various algorithms exist |
Important Facts:
- TSP is NP-Hard (optimization) and NP-Complete (decision version)
- No polynomial-time exact algorithm known (unless P=NP)
- Christofides gives 1.5-approximation for metric TSP
- Euclidean TSP admits PTAS (1+ε approximation)
- General TSP cannot be approximated within any constant factor (unless P=NP)
- Modern solvers can handle thousands of cities
- Record: Largest solved instance has 85,900 cities!
Why TSP is Important:
- Fundamental problem in optimization
- Benchmark for algorithm development
- Many real-world problems reduce to TSP
- Drives research in approximation algorithms
- Tests limits of computational methods