Skip to content

Commit 92a8d2c

Browse files
Merge pull request #546 from bhumikasahai/new-feature-branch
Added BellmanFord Algorithm of Dynamic Programming using java
2 parents b80189d + 9a1c46e commit 92a8d2c

2 files changed

Lines changed: 254 additions & 0 deletions

File tree

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
import java.util.Arrays;
2+
import java.util.List;
3+
import java.util.ArrayList;
4+
5+
// A class to represent the graph and run the Bellman-Ford algorithm
6+
class BellmanFord {
7+
8+
// A nested class to represent a weighted edge in the graph
9+
static class Edge {
10+
int source, destination, weight;
11+
12+
Edge(int source, int destination, int weight) {
13+
this.source = source;
14+
this.destination = destination;
15+
this.weight = weight;
16+
}
17+
}
18+
19+
private final int V; // Number of vertices
20+
private final List<Edge> edges; // List of all edges
21+
22+
public BellmanFord(int V) {
23+
this.V = V;
24+
this.edges = new ArrayList<>();
25+
}
26+
27+
public void addEdge(int source, int destination, int weight) {
28+
edges.add(new Edge(source, destination, weight));
29+
}
30+
31+
/**
32+
* Finds the shortest paths from a source vertex to all other vertices
33+
* in a weighted directed graph using the Bellman-Ford algorithm.
34+
*
35+
* ALGORITHM DESCRIPTION:
36+
* --------------------
37+
* The Bellman-Ford algorithm is a single-source shortest path algorithm that works on
38+
* directed, weighted graphs. Its key advantage over Dijkstra's algorithm is its ability
39+
* to handle graphs with negative edge weights. It can also detect if the graph
40+
* contains a negative-weight cycle that is reachable from the source.
41+
*
42+
* DYNAMIC PROGRAMMING & RELAXATION APPROACH:
43+
* The algorithm works by iteratively "relaxing" edges. A relaxation step for an edge (u, v)
44+
* with weight 'w' consists of checking if the shortest known path to 'v' can be improved
45+
* by going through 'u'.
46+
*
47+
* Core Idea:
48+
* If dist[u] + weight(u, v) < dist[v], then we update dist[v] = dist[u] + weight(u, v).
49+
*
50+
* Algorithm Steps:
51+
* 1. INITIALIZATION:
52+
* - Create a distance array `dist[]` of size V (number of vertices).
53+
* - Initialize the distance to the source vertex as 0.
54+
* - Initialize the distances to all other vertices as INFINITY.
55+
*
56+
* 2. ITERATIVE RELAXATION:
57+
* - Repeat the following loop V-1 times:
58+
* - For each edge (u, v) with weight 'w' in the graph:
59+
* - Perform the relaxation step: if `dist[u] + w < dist[v]`, update `dist[v]`.
60+
* - Why V-1 times? A simple shortest path in a graph with V vertices can have at most V-1 edges.
61+
* In the worst case, each iteration finds the next edge in the shortest path. After V-1
62+
* iterations, we guarantee that we have found all shortest paths if no negative cycle exists.
63+
*
64+
* 3. NEGATIVE CYCLE DETECTION:
65+
* - After the V-1 iterations, perform one final iteration over all edges.
66+
* - If for any edge (u, v), we can still perform a relaxation (i.e., if `dist[u] + w < dist[v]`),
67+
* it means the path can be shortened indefinitely. This is only possible if there is a
68+
* negative-weight cycle in the graph. In this case, the algorithm reports the cycle's existence.
69+
*
70+
* COMPLEXITY ANALYSIS:
71+
* --------------------
72+
* Time Complexity: O(V * E)
73+
* where V is the number of vertices and E is the number of edges.
74+
* The main logic consists of a loop that runs V-1 times (or V times, including the
75+
* cycle check), and inside this loop, we iterate over all E edges.
76+
*
77+
* Space Complexity: O(V)
78+
* This is the auxiliary space required to store the `dist` array. The space for the
79+
* graph representation itself (the edge list) is O(E). So total space is O(V + E).
80+
*
81+
* @param source The source vertex from which to find shortest paths.
82+
*/
83+
public void runBellmanFord(int source) {
84+
// Step 1: Initialize distances array.
85+
// Set distance to source as 0 and all others as infinite.
86+
int[] dist = new int[V];
87+
Arrays.fill(dist, Integer.MAX_VALUE);
88+
dist[source] = 0;
89+
90+
// Step 2: Relax all edges V-1 times.
91+
// A simple shortest path from source to any other vertex can have at most V-1 edges.
92+
for (int i = 1; i < V; ++i) {
93+
// Iterate through all edges in the graph
94+
for (Edge edge : edges) {
95+
int u = edge.source;
96+
int v = edge.destination;
97+
int weight = edge.weight;
98+
99+
// Perform the relaxation step
100+
// Check if a shorter path to 'v' is found through 'u'
101+
if (dist[u] != Integer.MAX_VALUE && dist[u] + weight < dist[v]) {
102+
dist[v] = dist[u] + weight;
103+
}
104+
}
105+
}
106+
107+
// Step 3: Check for negative-weight cycles.
108+
// This loop runs one more time (the V-th time) to detect cycles.
109+
for (Edge edge : edges) {
110+
int u = edge.source;
111+
int v = edge.destination;
112+
int weight = edge.weight;
113+
114+
// If we can still relax an edge, it means a negative cycle exists.
115+
if (dist[u] != Integer.MAX_VALUE && dist[u] + weight < dist[v]) {
116+
System.out.println("Graph contains a negative weight cycle!");
117+
return; // Exit if a cycle is detected
118+
}
119+
}
120+
121+
// If no negative cycle, print the distances
122+
printDistances(dist, source);
123+
}
124+
125+
private void printDistances(int[] dist, int source) {
126+
System.out.println("Shortest distances from source vertex " + source + ":");
127+
for (int i = 0; i < V; ++i) {
128+
if (dist[i] == Integer.MAX_VALUE) {
129+
System.out.println("Vertex " + i + " is unreachable.");
130+
} else {
131+
System.out.println("Vertex " + i + " \t at distance \t" + dist[i]);
132+
}
133+
}
134+
}
135+
136+
public static void main(String[] args) {
137+
int V = 5; // 5 vertices
138+
BellmanFord graph = new BellmanFord(V);
139+
140+
// Add edges to the graph
141+
graph.addEdge(0, 1, -1);
142+
graph.addEdge(0, 2, 4);
143+
graph.addEdge(1, 2, 3);
144+
graph.addEdge(1, 3, 2);
145+
graph.addEdge(1, 4, 2);
146+
graph.addEdge(3, 2, 5);
147+
graph.addEdge(3, 1, 1);
148+
graph.addEdge(4, 3, -3);
149+
150+
int sourceVertex = 0;
151+
graph.runBellmanFord(sourceVertex);
152+
153+
/*
154+
Example for Negative Cycle Detection:
155+
156+
int V_cycle = 4;
157+
BellmanFord cycleGraph = new BellmanFord(V_cycle);
158+
cycleGraph.addEdge(0, 1, 1);
159+
cycleGraph.addEdge(1, 2, -1);
160+
cycleGraph.addEdge(2, 3, -1);
161+
cycleGraph.addEdge(3, 0, -1); // This edge creates a negative cycle
162+
163+
System.out.println("\n--- Testing Graph with Negative Cycle ---");
164+
cycleGraph.runBellmanFord(0);
165+
*/
166+
}
167+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import java.sql.Time;
2+
import java.util.Arrays;
3+
4+
public class Knapsack {
5+
6+
//Description:
7+
// This function solves the 0/1 Knapsack problem to find the maximum value of items
8+
// that can fit within a limited weight capacity. It uses a bottom-up dynamic
9+
// programming approach by building a table of optimal solutions for all subproblems.
10+
11+
//Time Complexity: O(n * W)
12+
//- Where 'n' is the number of items and 'W' is the knapsack capacity.
13+
//- The complexity arises from the nested loops used to fill the DP table of size (n+1) x (W+1).
14+
15+
//Space Complexity: O(n * W)
16+
//- We use a 2D array (DP table) of size (n+1) x (W+1) to store the results of subproblems.
17+
18+
/**
19+
* Solves the 0/1 Knapsack problem using Dynamic Programming (Tabulation).
20+
*
21+
* @param weights An array of weights of the items.
22+
* @param values An array of values of the items.
23+
* @param capacity The maximum weight capacity of the knapsack.
24+
* @param n The number of items.
25+
* @return The maximum value that can be put in the knapsack.
26+
*/
27+
public int solveKnapsack(int[] weights, int[] values, int capacity) {
28+
int n = weights.length;
29+
30+
// dp[i][w] will be the maximum value that can be obtained
31+
// using the first 'i' items with a knapsack capacity of 'w'.
32+
// We use n+1 and capacity+1 to make indexing easier (1-based).
33+
int[][] dp = new int[n + 1][capacity + 1];
34+
35+
// Build table dp[][] in a bottom-up manner.
36+
for (int i = 0; i <= n; i++) {
37+
for (int w = 0; w <= capacity; w++) {
38+
// Base case: If there are no items (i=0) or the capacity is 0 (w=0),
39+
// the value is 0.
40+
if (i == 0 || w == 0) {
41+
dp[i][w] = 0;
42+
}
43+
// If the weight of the i-th item is less than or equal to the current capacity 'w'
44+
else if (weights[i - 1] <= w) {
45+
// We have two choices:
46+
// 1. Include the i-th item: value is values[i-1] + value from remaining capacity.
47+
// 2. Exclude the i-th item: value is the same as with i-1 items.
48+
// We take the maximum of these two choices.
49+
// Note: weights[i-1] and values[i-1] correspond to the i-th item.
50+
dp[i][w] = Math.max(
51+
values[i - 1] + dp[i - 1][w - weights[i - 1]], // Include item
52+
dp[i - 1][w] // Exclude item
53+
);
54+
}
55+
// If the weight of the i-th item is more than the current capacity 'w',
56+
// we cannot include it. So the value is the same as with i-1 items.
57+
else {
58+
dp[i][w] = dp[i - 1][w];
59+
}
60+
}
61+
}
62+
63+
// The final answer is in the bottom-right corner of the table.
64+
return dp[n][capacity];
65+
}
66+
67+
public static void main(String[] args) {
68+
Knapsack ks = new Knapsack();
69+
70+
int[] values = {60, 100, 120};
71+
int[] weights = {10, 20, 30};
72+
int capacity = 50;
73+
74+
int maxValue = ks.solveKnapsack(weights, values, capacity);
75+
76+
System.out.println("Items available:");
77+
System.out.println("Values: " + Arrays.toString(values));
78+
System.out.println("Weights: " + Arrays.toString(weights));
79+
System.out.println("Knapsack Capacity: " + capacity);
80+
System.out.println("Maximum value that can be obtained is: " + maxValue);
81+
82+
// Expected output for this example is 220.
83+
// This is achieved by taking the items with weight 20 (value 100) and 30 (value 120).
84+
// Total weight = 20 + 30 = 50.
85+
// Total value = 100 + 120 = 220.
86+
}
87+
}

0 commit comments

Comments
 (0)