diff --git a/src/main/java/com/williamfiset/algorithms/dp/DagDynamicProgramming.java b/src/main/java/com/williamfiset/algorithms/dp/DagDynamicProgramming.java
new file mode 100644
index 000000000..025fe7808
--- /dev/null
+++ b/src/main/java/com/williamfiset/algorithms/dp/DagDynamicProgramming.java
@@ -0,0 +1,125 @@
+package com.williamfiset.algorithms.dp;
+
+import java.util.*;
+
+/**
+ * Dynamic Programming on Directed Acyclic Graphs (DAG).
+ *
+ *
+ * This implementation demonstrates how to apply dynamic programming on a DAG
+ * using a topological ordering (Kahn's algorithm).
+ *
+ *
+ * Example use-case: counting the number of ways to reach each node from a
+ * source.
+ *
+ *
+ * Time Complexity: O(V + E)
+ * Space Complexity: O(V + E)
+ */
+public class DagDynamicProgramming {
+
+ // Minimal edge representation (only what is needed)
+ public static class Edge {
+ int to;
+
+ public Edge(int to) {
+ this.to = to;
+ }
+ }
+
+ /**
+ * Performs topological sorting using Kahn's algorithm.
+ */
+ public static int[] kahnTopoSort(Map> graph, int numNodes) {
+
+ int[] indegree = new int[numNodes];
+
+ // Compute indegree
+ for (int u = 0; u < numNodes; u++) {
+ for (Edge edge : graph.getOrDefault(u, Collections.emptyList())) {
+ indegree[edge.to]++;
+ }
+ }
+
+ Queue q = new ArrayDeque<>();
+ for (int i = 0; i < numNodes; i++) {
+ if (indegree[i] == 0)
+ q.add(i);
+ }
+
+ int[] topo = new int[numNodes];
+ int index = 0;
+
+ while (!q.isEmpty()) {
+ int u = q.poll();
+ topo[index++] = u;
+
+ for (Edge edge : graph.getOrDefault(u, Collections.emptyList())) {
+ if (--indegree[edge.to] == 0) {
+ q.add(edge.to);
+ }
+ }
+ }
+
+ // Cycle detection
+ if (index != numNodes)
+ return new int[0];
+
+ return topo;
+ }
+
+ /**
+ * Counts number of ways to reach each node from a source in a DAG.
+ */
+ public static long[] countWaysDAG(
+ Map> graph, int source, int numNodes) {
+
+ int[] topo = kahnTopoSort(graph, numNodes);
+ if (topo.length == 0)
+ return null;
+
+ long[] dp = new long[numNodes];
+ dp[source] = 1;
+
+ for (int u : topo) {
+ if (dp[u] == 0L)
+ continue;
+
+ for (Edge edge : graph.getOrDefault(u, Collections.emptyList())) {
+ dp[edge.to] += dp[u];
+ }
+ }
+
+ return dp;
+ }
+
+ public static void main(String[] args) {
+
+ final int N = 6;
+ Map> graph = new HashMap<>();
+
+ for (int i = 0; i < N; i++) {
+ graph.put(i, new ArrayList<>());
+ }
+
+ // Example DAG
+ graph.get(0).add(new Edge(1));
+ graph.get(0).add(new Edge(2));
+ graph.get(1).add(new Edge(3));
+ graph.get(2).add(new Edge(3));
+ graph.get(3).add(new Edge(4));
+
+ int source = 0;
+
+ long[] dp = countWaysDAG(graph, source, N);
+
+ if (dp == null) {
+ System.out.println("Graph contains a cycle!");
+ return;
+ }
+
+ System.out.println("Ways from source:");
+ System.out.println(Arrays.toString(dp));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/williamfiset/algorithms/dp/DagDynamicProgrammingTest.java b/src/test/java/com/williamfiset/algorithms/dp/DagDynamicProgrammingTest.java
new file mode 100644
index 000000000..9fdb47326
--- /dev/null
+++ b/src/test/java/com/williamfiset/algorithms/dp/DagDynamicProgrammingTest.java
@@ -0,0 +1,72 @@
+package com.williamfiset.algorithms.dp;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.*;
+
+import org.junit.jupiter.api.Test;
+
+public class DagDynamicProgrammingTest {
+
+ private Map> createGraph(int n) {
+ Map> graph = new HashMap<>();
+ for (int i = 0; i < n; i++) {
+ graph.put(i, new ArrayList<>());
+ }
+ return graph;
+ }
+
+ @Test
+ public void testSimpleDAGWays() {
+
+ int n = 5;
+ Map> graph = createGraph(n);
+
+ graph.get(0).add(new DagDynamicProgramming.Edge(1));
+ graph.get(0).add(new DagDynamicProgramming.Edge(2));
+ graph.get(1).add(new DagDynamicProgramming.Edge(3));
+ graph.get(2).add(new DagDynamicProgramming.Edge(3));
+ graph.get(3).add(new DagDynamicProgramming.Edge(4));
+
+ long[] dp = DagDynamicProgramming.countWaysDAG(graph, 0, n);
+
+ assertNotNull(dp);
+ assertEquals(1, dp[0]);
+ assertEquals(1, dp[1]);
+ assertEquals(1, dp[2]);
+ assertEquals(2, dp[3]); // 0->1->3 and 0->2->3
+ assertEquals(2, dp[4]);
+ }
+
+ @Test
+ public void testDisconnectedGraph() {
+
+ int n = 4;
+ Map> graph = createGraph(n);
+
+ graph.get(0).add(new DagDynamicProgramming.Edge(1));
+
+ long[] dp = DagDynamicProgramming.countWaysDAG(graph, 0, n);
+
+ assertNotNull(dp);
+ assertEquals(1, dp[0]);
+ assertEquals(1, dp[1]);
+ assertEquals(0, dp[2]); // unreachable
+ assertEquals(0, dp[3]); // unreachable
+ }
+
+ @Test
+ public void testCycleDetection() {
+
+ int n = 3;
+ Map> graph = createGraph(n);
+
+ graph.get(0).add(new DagDynamicProgramming.Edge(1));
+ graph.get(1).add(new DagDynamicProgramming.Edge(2));
+ graph.get(2).add(new DagDynamicProgramming.Edge(0)); // cycle
+
+ long[] dp = DagDynamicProgramming.countWaysDAG(graph, 0, n);
+
+ assertNull(dp); // cycle detected
+ }
+}
\ No newline at end of file