Dynamic Programming for Minimum Path Sum - c++

I am not understanding how to exactly use dynamic programming for the Minimum Path Sum Problem. The problem statement is as follows.
Given a m x n grid filled with non-negative numbers, find a path from
top left to bottom right which minimizes the sum of all numbers
along its path.
Note: You can only move either down or right at any point in time.
Here is the code i tried using just recursion.
#include "stdafx.h"
#include "vector"
#include "iostream"
#include "cmath"
#include "algorithm"
using namespace std;
class Solution {
public:
int s = INT_MAX;
int helper(int sum, vector<vector<int>> &grid, int i, int j) {
if (i == grid.size() - 1 && j == grid[0].size() - 1) {
return s = min(s, sum + grid[i][j]);
}
if (i >= grid.size() || j >= grid[0].size()) {
return sum;
}
return min(helper(sum + grid[i][j], grid, i + 1, j) + helper(sum + grid[i][j], grid, i, j + 1), s);
}
int minPathSum(vector<vector<int>>& grid) {
return helper(0, grid, 0, 0);
}
};
int main()
{
vector<int> v = { 1,2,3 };
vector<vector<int>> r;
r.push_back(v);
v = { 4,5,6 };
r.push_back(v);
v = { 7,8,9 };
r.push_back(v);
v = { 1,2,3 };
r.push_back(v);
Solution s;
cout<<s.minPathSum(r);
return 0;
}
And here is a code where i tried using Dynamic programming where I am storing the least sum at a given index [i,j] and returning it, but its not being of much help, the Online Coding Judge says "Time Limit Exceeded"
Can you please help me improve the code.
#include "stdafx.h"
#include "vector"
#include "iostream"
#include "cmath"
#include "algorithm"
using namespace std;
class Solution {
public:
int s = INT_MAX;
int helper(int sum, vector<vector<int>> &grid, int i, int j,vector<vector<int>> &memoize) {
if (i == grid.size() - 1 && j == grid[0].size() - 1) {
return s = min(s, sum + grid[i][j]);
}
if (i >= grid.size() || j >= grid[0].size()) {
return sum;
}
if (sum + grid[i][j] < memoize[i][j])
memoize[i][j] = sum + grid[i][j];
else
return memoize[i][j];
return min(helper(sum + grid[i][j], grid, i + 1, j,memoize) + helper(sum + grid[i][j], grid, i, j + 1,memoize), s);
}
int minPathSum(vector<vector<int>>& grid) {
vector<vector<int>> memoize(grid.size(), vector<int>(grid[0].size(), INT_MAX));
return helper(0, grid, 0, 0,memoize);
}
};
int main()
{
vector<int> v = { 1,2,3 };
vector<vector<int>> r;
r.push_back(v);
v = { 4,5,6 };
r.push_back(v);
v = { 7,8,9 };
r.push_back(v);
v = { 1,2,3 };
r.push_back(v);
Solution s;
cout<<s.minPathSum(r);
return 0;
}

Related

Dynamic programming - Gold mine grid optimization TLE

I'm trying to solve Gold Mine problem from https://practice.geeksforgeeks.org/problems/gold-mine-problem2608/1/#. I am receiving TLE for the following code. I have looked at the solution also yet dont understand what minor mistake I made that the code received TLE and the solution code.
class Solution{
public:
int helper(int a , int b, int n , int m , vector<vector<int>> M, vector<vector<int>> &N){
if(a<0 || b<0 || a>=n){
return INT_MIN ;
}
if(N[a][b]!=-1){
return N[a][b];
}
if(b==m){
N[a][b] = 0;
return 0;
}
else{
N[a][b] = M[a][b] + max( (helper(a+1,b+1,n,m,M,N)) , max(helper(a-1,b+1,n,m,M,N),helper(a,b+1,n,m,M,N)));
return N[a][b] ;
}
// return N[a][b];
}
int maxGold(int n, int m, vector<vector<int>> M)
{
// code here
vector<vector<int>> N(n,vector<int>(m+1,-1) );
int ans = 0 ;
for(int i=0; i<n; i++){
// int ans2 = helper(i,0,n,m,M,N);
// if(ans2>ans){
// ans = ans2;
// }
ans = max(ans,helper(i,0,n,m,M,N));
}
return ans;
// just one extra in right to store 0s
// position a,b to a,b
// n,m to n-1,m-1
}
};
The solution given on the site :
// C++ program to solve Gold Mine problem
#include<bits/stdc++.h>
using namespace std;
int collectGold(vector<vector<int>> gold, int x, int y, int n, int m, vector<vector<int>> &dp) {
// Base condition.
if ((x < 0) || (x == n) || (y == m)) {
return 0;
}
if(dp[x][y] != -1){
return dp[x][y] ;
}
// Right upper diagonal
int rightUpperDiagonal = collectGold(gold, x - 1, y + 1, n, m, dp);
// right
int right = collectGold(gold, x, y + 1, n, m, dp);
// Lower right diagonal
int rightLowerDiagonal = collectGold(gold, x + 1, y + 1, n, m, dp);
// Return the maximum and store the value
return dp[x][y] = gold[x][y] + max(max(rightUpperDiagonal, rightLowerDiagonal), right);
}
int getMaxGold(vector<vector<int>> gold, int n, int m)
{
int maxGold = 0;
// Initialize the dp vector
vector<vector<int>> dp(n, vector<int>(m, -1)) ;
for (int i = 0; i < n; i++) {
// Recursive function call for ith row.
int goldCollected = collectGold(gold, i, 0, n, m, dp);
maxGold = max(maxGold, goldCollected);
}
return maxGold;
}
I suppose that calculating all 3 directions differently and then taking max seems to make the actual solution faster, but would like to understand the reason for the same to improve myself.
EDIT1 - Nope, still received TLE after calculating differently for all 3 directions, although it did manage to do more test cases which I dont understand why.

How to find indexes of elements in recursive-knapsack?

I'm trying to implement recursive Knapsack which would return 2 things:
Max value we get by filling knapsack.
Indexes of the elements considered for filling the knapsack.
Please note that I don't want to use Dynamic Programming Approach to get this done (by reverse iterating the 2-D matrix to get the indexes of elements). I want to understand how it can be done in recursive knapsack approach?
This is what I have tried below (getting correct MaxValue (op#1) BUT not getting correct list of indexes (op#2)):
int knapsack(vector<int> wt, vector<int> val, int W, int N, vector<int>& idx)
{
if (W == 0 || N == 0) return 0;
if (wt[N - 1] <= W)
{
int consider = val[N - 1] + knapsack(wt, val, W - wt[N - 1], N - 1, idx);
int dontconsider = knapsack(wt, val, W, N - 1, idx);
if (consider > dontconsider)
{
idx.push_back(N-1);
}
return max(consider, dontconsider);
}
else
{
return knapsack(wt, val, W, N - 1, idx);
}
}
int main()
{
vector<int> wt = { 10, 20, 30 };
vector<int> val = { 60, 100, 120 };
int W = 50;
vector<int> idx; // this should retain the indexes of the elements considered for knapsack.
cout << knapsack(wt, val, W, wt.size(), idx);
cout << "\nIndex of elements considered for knapsack: ";
for (int i = 0; i < idx.size(); i++)
cout << idx[i] << " ";
getchar();
return 0;
}
Expected output should be:
220
Index of elements considered for knapsack: 1 2
Please help me. Thank you.
The vector idx is passed by reference: vector<int>& idx.
The issue is that here:
int consider = val[N - 1] + knapsack(wt, val, W - wt[N - 1], N - 1, idx);
int dontconsider = knapsack(wt, val, W, N - 1, idx);
This vector idx is modified twice.
One solution is to create a temporary vector for the first call...
#include <iostream>
#include <vector>
#include <algorithm>
int knapsack(const std::vector<int>& wt, const std::vector<int>& val, int W, int N, std::vector<int>& idx) {
if (W == 0 || N == 0) return 0;
if (wt[N - 1] <= W) {
std::vector<int> idx0;
int consider = val[N - 1] + knapsack(wt, val, W - wt[N - 1], N - 1, idx0);
int dontconsider = knapsack(wt, val, W, N - 1, idx);
if (consider > dontconsider) {
idx = idx0;
idx.push_back(N-1);
return consider;
}
return dontconsider;
}
else {
return knapsack(wt, val, W, N - 1, idx);
}
}
int main()
{
std::vector<int> wt = { 10, 20, 30 };
std::vector<int> val = { 60, 100, 120 };
int W = 50;
std::vector<int> idx; // this should retain the indexes of the elements considered for knapsack.
std::cout << knapsack(wt, val, W, wt.size(), idx);
std::
cout << "\nIndex of elements considered for knapsack: ";
for (int i = 0; i < idx.size(); i++)
std::cout << idx[i] << " ";
std::cout << "\n";
//getchar();
return 0;
}
Damien's diagnostic is correct. The problem is the repetition of already considered entries in the idx vector in the multiple evaluated branches of the iterations.
I would only add a new approach which I think would be more simple. Instead of using a vector, you can simply change your code making idx a set object, which is a container like a vector, but with one important difference: it does not allow repeated elements. So, if you insert an element already contained in a set, it will not add a new one.
#include <iostream>
#include <vector>
#include <algorithm>
#include <set>
using namespace std;
int knapsack(const vector<int> wt, const vector<int> val, const int W, int N, set<int>& idx)
{
if (W == 0 || N == 0) return 0;
if (wt[N - 1] <= W)
{
int consider = val[N - 1] + knapsack(wt, val, W - wt[N - 1], N - 1, idx);
int dontconsider = knapsack(wt, val, W, N - 1, idx);
if (consider > dontconsider)
{
idx.insert(N-1);
}
return max(consider, dontconsider);
}
else
{
return knapsack(wt, val, W, N - 1, idx);
}
}
int main()
{
vector<int> wt = { 10, 20, 30 };
vector<int> val = { 60, 100, 120 };
int W = 50;
set<int> idx; // this should retain the indexes of the elements considered for knapsack.
cout << "Maximum value obtained: " << knapsack(wt, val, W, wt.size(), idx);
cout << "\nIndex of elements considered for knapsack: ";
for (auto i : idx)
cout << i << " ";
cout << endl;
getchar();
return 0;
}
Here is my example code using a set (note I had to make small adjustments, since there are some methods like pusk_back that are vector specific):

0-1 Knapsack C++ not returning proper value

#include<bits/stdc++.h>
using namespace std;
int knapsackTab(int val[],int wt[], int W, int n)
{
int dp[n+1][W+1];
for(int i=0;i<n+1;i++){
for(int j=0;j<W+1;j++){
if(i==0||j==0)
dp[i][j]=0;
if(wt[i-1]<=j)
dp[i][j] = max(val[i-1] + dp[i-1][j-wt[i-1]],dp[i-1][j]);
else
dp[i][j] = dp[i-1][j];
}
}
return dp[n][W];
}
int main()
{
int val[] = { 10, 20, 30 };
int wt[] = { 1, 1, 1 };
int W = 2;
int n = sizeof(val) / sizeof(val[0]);
cout<<knapsackTab(val,wt,W,n);
}
The output is a huge number. I assume its a garbage value.
Expected Output : 50
Pls help me and tell me where I might be making the mistake
You forgot else after the i==0||j==0 check, so out-of-range values are read.
if(i==0||j==0)
dp[i][j]=0;
else if(wt[i-1]<=j) // add "else" here
dp[i][j] = max(val[i-1] + dp[i-1][j-wt[i-1]],dp[i-1][j]);
else
dp[i][j] = dp[i-1][j];

Finding minimum total length of line segments to connect 2N points

I'm trying to solve this problem by bruteforce, but it seems to run very slow when given 7 (which is 2*7 points).
Note: I only need to run it to maximum 2*8 points
Problem statement:
Given 2*N points in a 2d plane, connect them in pairs to form N line segments. Minimize the total length of all the line segments.
Example:
Input: 5 10 10 20 10 5 5 1 1 120 3 6 6 50 60 3 24 6 9 0 0
Output: 118.4
#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
#include <iomanip>
using namespace std;
class point{
public:
double x, y;
};
double getLength(point a, point b){
return hypot((a.x - b.x), (a.y - b.y));
}
static double mini = INT_MAX;
void solve(vector <point> vec, double sum){
double prevSum = sum;
if(sum > mini){
return;
}
if(vec.size() == 2){
sum += getLength(vec[0], vec[1]);
mini = min(mini, sum);
return;
}
for(int i = 0; i < vec.size() - 1; i++){
for(int j = i + 1; j < vec.size(); j++){
sum = prevSum;
vector <point> temp = vec;
sum += getLength(temp[i], temp[j]);
temp.erase(temp.begin() + j);
temp.erase(temp.begin() + i);
solve(temp, sum);
}
}
}
int main(){
point temp;
int input;
double sum = 0;
cin >> input;
vector<point> vec;
for(int i = 0; i < 2 * input; i++){
cin >> temp.x >> temp.y;
vec.push_back(temp);
}
solve(vec, sum);
cout << fixed << setprecision(2) << mini << endl;
}
How can I speed up this code ?
I don't think this is what you are looking for but I mention it for completeness sake anyway. The problem can be formulated as a Mixed Integer Programming (MIP) problem.
We have distances:
d(i,j) = distance between point i and j (only needed for i<j)
and decision variables
x(i,j) = 1 if points i and j are connected (only needed for i<j)
0 otherwise
Then we can write:
Solving this problem can be done with widely available MIP solvers and leads to proven optimal solutions. A small example with 50 points:
You can solve this iteratively by using next_permutation() to go through all the permutations one by one. Apologies for the messy code, but this should show you how to do it:
struct Point {
Point(int x, int y) : x(x), y(y) {
}
bool operator< (const Point& rhs) {
const int key1 = y * 1000 + x;
const int key2 = rhs.y * 1000 + rhs.x;
return key1 < key2;
}
double dist(const Point& next) {
const double h = (double)(next.x - x);
const double v = (double)(next.y - y);
return sqrt(h*h + v*v);
}
int x, y;
};
You need the operator so you have some sort of sorting key for your points, so next_permutation can go through them in lexicographical increasing order.
double getShortestDist(std::vector p) {
double min = 200000;
std::sort(p.begin(), p.end());
while(std::next_permutation(p.begin(), p.end())) {
double sum = 0.0;
for (int i = 0; i < p.size(); i+= 2) {
sum += p[i].dist(p[i+1]);
}
if (sum < min) {
min = sum;
}
}
return min;
}
int main(int argc, char*argv[]) {
static const int arr[] = {
10, 10, 20, 10, 5, 5, 1, 1, 120, 3, 6, 6, 50, 60, 3, 24, 6, 9, 0, 0
};
std::vector<Point> test;
for (int i = 0; i < 20; i += 2) {
test.push_back(Point(arr[i], arr[i+1]));
printf("%d %d\n", arr[i], arr[i+1]);
}
printf("Output: %d, %f", test.size(), getShortestDist(test));
}

Use C++ armadillo Expectation Maximization for Gaussian mixture model

I am trying to use armadillo's expectation maximization maximization gmm_diag class, but when I try to compile it I get "error gmm_diag was not declared in this scope".
My code is as follows:
#include <stdio.h>
#include <iostream>
#include <vector>
#include <armadillo>
#include <omp.h>
using namespace std;
using namespace arma;
int main()
{
// create synthetic data with 2 Gaussians
uword N = 10000;
uword d = 5;
mat data(d, N, fill::zeros);
vec mean0 = linspace<vec>(1,d,d);
vec mean1 = mean0 + 2;
uword i = 0;
while(i < N)
{
if(i < N) { data.col(i) = mean0 + randn<vec>(d); ++i; }
if(i < N) { data.col(i) = mean0 + randn<vec>(d); ++i; }
if(i < N) { data.col(i) = mean1 + randn<vec>(d); ++i; }
}
gmm_diag model;
model.learn(data, 2, maha_dist, random_subset, 10, 5, 1e-10, true);
model.means.print("means:");
double scalar_likelihood = model.log_p( data.col(0) );
rowvec set_likelihood = model.log_p( data.cols(0,9));
double overall_likelihood = model.avg_log_p(data);
uword gaus_id = model.assign( data.col(0), eucl_dist );
urowvec gaus_ids = model.assign( data.cols(0,9), prob_dist );
urowvec hist1 = model.raw_hist (data, prob_dist);
rowvec hist2 = model.norm_hist(data, eucl_dist);
model.save("my_model.gmm");
// the table is now initialized
}