Any suggestion on finding a standard tabulation way to solve this - c#

I have this question:
Given a grid of positive numbers, start from 0,0 and end at n,n.
Move only to right and down.
Find path with sum of numbers is maximum.
Input Example:
5 1 2
6 7 8
1 4 9
output Example:
35
I solved it with many scenarios for example i wrote an easy equation to get the max path length then take some decisions to get the correct result.
But this example is easy to got that it should solved using dynamic programming as it's recursion and some overlaps with small space:
fn(0,0)
fn(0,1) f(1,0)
f(0,2) f(1,1) f(2,0) f(1,1)
I solved it easy using Memoization technique:
public int GetMaxPathTopDown(int r, int c, int[,] arr, int[,] mem)
{
if (r >= arr.GetLength(0) || c >= arr.GetLength(1))
{
return 0;
}
// Base Case
if (r == arr.GetLength(0) - 1 && c == arr.GetLength(1) - 1)
{
return arr[r, c];
}
if (mem[r, c] != -1)
{
return mem[r, c];
}
int firstPath = GetMaxPathTopDown(r, c + 1, arr, mem);
int secondPath = GetMaxPathTopDown(r + 1, c, arr, mem);
return mem[r, c] = arr[r, c] + Math.Max(firstPath, secondPath);
}
but I want to find standard solution to solve it using Tabulation way. I tried many solutions but i thought it's not a correct way of tabulation so any help?

#Marzouk, you can try this:
dp[i, j] will be the maximum sum you can get from (0, 0) to (i, j). Now, dp[i, j] will depend on dp[i - 1, j] and dp[i, j - 1]. So, the recurrence will be:
dp[i, j] = max(dp[i - 1, j], dp[i, j - 1]) + mt[i, j]
You need to handle corner cases here (i = 0 or j = 0).
using System;
class MainClass {
public static void Main (string[] args) {
int[,] mt = new[,] { {5, 1, 2}, {6, 7, 8}, {1, 4, 9} };
int[,] dp = new[,] { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} };
int R = mt.GetLength(0);
int C = mt.GetLength(1);
for (int i = 0; i < R; i++)
for (int j = 0; j < C; j++) {
dp[i, j] = mt[i, j];
if (i > 0 && j > 0) {
dp[i, j] += Math.Max(dp[i - 1, j], dp[i, j - 1]);
} else if (i > 0) {
dp[i, j] += dp[i - 1, j];
} else if (j > 0) {
dp[i, j] += dp[i, j - 1];
}
}
Console.WriteLine(dp[R-1, C-1]);
}
}

The basic steps to build bottom-up dynamic programming solutions are as follows:
1- Determine the required set of parameters that uniquely describe the problem (the state).
2- If there are N parameters required to represent the states, prepare an N dimensional DP table, with one entry per state.
This is equivalent to the memo table in top-down DP. However, there are differences. In bottom-up DP, we only need to initialize some cells of the DP table with known initial values (the base cases). Recall that in topdown DP, we initialize the memo table completely with dummy values (usually -1) to indicate that we have not yet computed the values.
3- Now, with the base-case cells/states in the DP table already filled, determine the cells/states that can be filled next (the transitions).
Repeat this process until the DP table is complete.
For the bottom-up DP, this part is usually accomplished through iterations, using loops.
lets build a table for 3*3 array with values:
5 1 2
3 1 2
0 1 1
we notice that we need two parameters : Move_right, Move_down
initially, the first row and column should have the cumulative sum of the array elements to start maximization
then follow the steps in the attached picture which explain the code below
dp[0,0] = arr[0,0];
for (int i = 1; i < n; i++){
dp[0,i] = arr[0,i] + dp[0,i - 1];
}
for (int i = 1; i < n; i++){
dp[i,0] = arr[i,0] + dp[i-1,0];
}
for (int i = 1; i < n; i++){
for (int j = 1; j < n; j++){
dp[i,j] = arr[i,j] + Math.max(dp[i - 1,j], dp[i,j - 1]);
}
}
Console.WriteLine(dp[n - 1,n - 1]);
the required answer should be 12, and you find it in the most right-down cell
building table

Related

Maximum sum path in a matrix from top to bottom

Consider a n*m matrix. Suppose each cell in the matrix has a value assigned. We can start from each cell in first row in matrix. The allowed moves are diagonally left, downwards or diagonally right, i.e, from location (i, j) next move can be (i+1, j), or, (i+1, j+1), or (i+1, j-1). (If index is not outside the bounds of the array of course)
Let an additional restriction be added: only paths are allowed that pass (at least once) through all the columns.
Find the maximum sum of elements satisfying the allowed moves.
For example for matrix:
1 15 2
9 7 5
9 2 4
6 9 -1
The sum is equal:
28
Because the path is 15+5+2+6=28.
The main feature is that I need to use a dynamic approach. For a task without restriction about all the columns I could do:
var matrix = new int[,]{ { 1, 15, 2 }, //start matrix
{ 9, 7, 5 },
{ 9, 2, 4},
{ 6, 9, -1 } };
long n = matrix.GetLength(0);
long m = matrix.GetLength(1);
var sum = new List<long[]>(); // list [n][m] of maxsums
for (int i = 0; i < n; i++)
{
sum.Add(new long[m].Select(e => e = long.MinValue).ToArray());
}
for (int i = 0; i < m; i++)
{
sum[0][i] = matrix[0, i]; //sums at first line equal first line in matrix
}
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < m; j++)
{
if (j > 0) sum[i + 1][j - 1] = Math.Max(sum[i][j] + matrix[i + 1, j - 1], sum[i + 1][j - 1]); // diagonally left
sum[i + 1][j] = Math.Max(sum[i][j] + matrix[i + 1, j], sum[i + 1][j]); // downwards
if (j < m - 1) sum[i + 1][j + 1] = Math.Max(sum[i][j] + matrix[i + 1, j + 1], sum[i + 1][j + 1]); //diagonally right
}
}
long max = sum[(int)n - 1].Max(); //maximum sum among all paths (answer)
And for the same matrix the maximum sum will equal:
42
Because the path is 15+9+9+9=42
Нow I can calculate a dynamics matrix for all paths and sums with restriction?
An easy way to do this is with a Queue.
Add the first row
for every item in the queue, add any other valid moves
when finished, check if it's a valid combination
check against the last highest
It uses an and Iterator method, Linq, and queues to return current best finds. What I suggest you do, is research the parts involved, step through it and inspect variables, use Console.WriteLine to look at what is happening. If you are really stuck you can always ask further questions about this code and what it's doing.
The idea of the queue is, we add each element in the first row as initial items in the queue (that is our precondition by the rules you have given), then we go and look at the first element in the queue, then from that position (x,y) we go through all the next positions in the next row that we can legitimately visit. The queue also hold a list of columns visited and a value at that position. It could be done differently. I.e we really only need to to know the sum of all elements visited and a list of columns etc so we can validate the path afterwards.
Note : This is not the most optimal solution and it could be done a lot more efficiently and in less code in many other ways (and more elegantly). However, it touches on a lot of common concepts that are worth understanding
Given
private static Random _rand = new Random();
// this could be done with linq, however it's easy to see how it works
private static bool IsPathValid(int length, List<int> path)
{
for (var i = 0; i < length; i++)
if (!path.Contains(i))
return false;
return true;
}
Iterator
public static IEnumerable<IEnumerable<(int col, int value)>> FindPath(int[, ] matrix)
{
var queue = new Queue<(int x, int y, List<(int col, int value)> path)>();
// add the first row to the queue
for (var i = 0; i < matrix.GetLength(1); i++)
queue.Enqueue((i, 0, new List<(int col, int value)>()));
// lets keep the higest found
var highest = int.MinValue;
// loop all queue items until none left
while (queue.Any())
{
// get the next item out of the queue
var(x, y, path) = queue.Dequeue();
// add the path we are visiting
path.Add((x, matrix[y, x]));
// if we have looked at all the rows, then time to return
if (y + 1 == matrix.GetLength(0))
{
// get a list of columns visited
var cols = path.Select(x => x.col).ToList();
// check to see if all columns are visited
if (IsPathValid(matrix.GetLength(1), cols))
{
var sum = path.Sum(x => x.value);
// sum the path, if it's not the highest we don't care
if (sum > highest)
{
// we are the highest path so far so let's return it
yield return path;
highest = sum;
}
}
continue;
}
// where ever we are, lets look at all the valid x's in the next row
var start = Math.Max(0, x - 1);
var finish = Math.Min(matrix.GetLength(1) - 1, x + 1);
// add them to the queue
// we inefficiently create a new path, as list is a reference type and we don't want to reuse it
for (var newX = start; newX <= finish; newX++)
queue.Enqueue((newX, y + 1, new List<(int col, int value)>(path)));
}
}
Usage
// create a random matrix, make sure there the dimensions are going to produce a result
var y = _rand.Next(2, 5);
var matrix = new int[_rand.Next(y, y + 3), y];
// fill and print the matrix
Console.WriteLine("Matrix");
Console.WriteLine();
for (var i = 0; i < matrix.GetLength(0); i++)
{
for (var j = 0; j < matrix.GetLength(1); j++)
{
matrix[i, j] = _rand.Next(0, 20);
Console.Write(matrix[i, j].ToString().PadLeft(3));
}
Console.WriteLine();
}
Console.WriteLine();
Console.WriteLine("Best Path (column,Value)");
Console.WriteLine();
// get the best, which be the last
var best = FindPath(matrix).Last();
foreach (var item in best)
{
Console.WriteLine(item);
}
// show the result
Console.WriteLine();
Console.WriteLine("= " + best.Sum(x => x.value));
Output
Matrix
14 9 17 0
19 5 11 10
17 12 9 13
3 11 2 5
0 0 12 15
Best Path (column,Value)
(0, 14)
(0, 19)
(1, 12)
(2, 2)
(3, 15)
= 62
Full Demo Here
Additional Resources
Iterators
Tuple types (C# reference)
Array.GetLength(Int32) Method
Multidimensional Arrays (C# Programming Guide)
Random.Next Method
Queue Class
List.Contains(T) Method
Enumerable.Any Method
Enumerable.Sum Method
Enumerable.Last Method
Math.Min Method
Math.Max Method
continue (C# Reference)
Enumerable.Select Method
Enumerable.ToList methd

How can I add 2 binary int arrays in C#

I'm a programming student and I need a function that would add 2 binary int arrays in C#. I need to use the %. I spent the day looking for a way to do it but I don't find anything. How would you guys make it? The 2 numbers to add will always have the same amount of bits
I tried this
for(int i = nb1.Length; i>= 0; i--) {
reponse[i] = (nb1[i] + nb2[i]) % 2;
}
But it's not working because I need to count the number of cycle that I skipped
I want something like this
int[] nb1 = [0, 0, 1, 1]
int[] nb2 = [0, 1, 0, 1]
expected output = [1, 0, 0, 0]
Thanks!
The idea is to sum it up as ordinary numbers, but with base of 2
int mem = 0;
for(int i = nb1.Length; i>= 0; i--) {
reponse[i] = (mem + nb1[i] + nb2[i]) % 2;
mem = mem + nb1[i] + nb2[i] >= 2 ? 1 : 0;
}
if (mem != 0) {
response.Add(1);
}

moving an element in 2d array with arrow keys and having border restricting movement

I dont know if this has been answered before but how would I move an element in 2d array with arrow keys? say something like this and having it not move if it is not possible as in the image displayed 0 can swap and go up, down, left and right but the next move you are restricted to just three options as up,down and left only
New to c# so if there are helpful examples online about my problem just post them down the comment
using System;
namespace moveElement
{
public class move
{
static void Main(string[] args)
{
int[,] arr = { { 9, 1, 4 }, { 5, 0, 3 }, { 6, 8, 2 } };
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
Console.Write(arr[i, j] + " ");
}
Console.WriteLine();
}
}
}
}
Took what was suggested and made it work somehow like this
ConsoleKeyInfo info = Console.ReadKey();
if (info.Key == ConsoleKey.RightArrow)
{
int temp = arr[1, 1];
arr[1, 1] = arr[1, 2];
arr[1, 2] = temp;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
Console.Write(arr[i, j] + " ");
}
Console.WriteLine();
}
}
After working on the code for sometime I get error "use of unassigned local variable x and y" on line 41(y) and 47(x) I have completed most of the problem but stuck on this error
using System;
namespace moveElement
{
public class move
{
static void Main(string[] args)
{
int x, y;
int[,] arr = { { 0, 1, 4 }, { 3, 9, 5 }, { 6, 8, 2 } };
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
Console.Write(arr[i, j] + " ");
Solved the problem by giving x and y a value of 0.
You could try something similar to the answer of this post where you take the variable of position 1, put it in a temp variable, then set position 1 to the value of position 2 and finally set the value of position 2 to what is in the temp variable:
var t = a;
a = b;
b = t;
To actually figure out if you can move in a specific direction, you will need to check if you are at a boundary, for example, the boundaries would be (where i is any valid position):
arr[0, i]
arr[arr.getLength(0)-1, i]
arr[i, 0]
arr[i, arr.getLength(1)-1]
if your current position is the same as one of those, you will need to add some conditions so that you cant move in a specific direction, for example, if you have arr[0, i], you cannot move up one as it will then go to arr[-1, i] which does not exist.
I would suggest reading up on the Array.getLength(Int32 dimension) method for finding the boundaries (it essentially gets the length of the array at a specified dimension)

Find Maximum difference between two numbers in list using Bitwise AND

Hi all i am solving a problem that says :
Given a set S = {1, 2, 3, ... N}. Find two integers A and B where (A < B), from set S such that the value of A&B, where '&' is bitwise AND, is the maximum possible number less than a given integer K.
Sample Input1 : 5 2, (where n = 5, k = 2) => Output : 1,
Sample Input2 : 8 5, (where n = 8, k = 5) => Output : 4
I wrote the code and this seems to be working fine. But I am looking for more optimized solution. I am currently using two while loops, which I am not sure could be reduced to one single while or for loop. Below is my function :
static void Main(String[] args)
{
string[] tokens_n = Console.ReadLine().Split(' ');
int n = Convert.ToInt32(tokens_n[0]);
int k = Convert.ToInt32(tokens_n[1]);
int i = 1, maxDiff = 0;
while (i < n)
{
int j = i + 1;
while (j <= n)
{
int diff = i & j;
if (diff < k)
{
if (diff > maxDiff)
{
maxDiff = diff;
}
}
j++;
}
i++;
}
Console.WriteLine(maxDiff);
}
I found a solution here but that problem seems to be about finding maximum difference in two arbitrary numbers in a list, whereas i need to loop for all the combinations to find the Bitwise AND value and then compare it.
int maxAnd = INT_MIN;
for(int i = 1; i < k; i++) {
for(int j = i + 1; j <= n; j++) {
int currentAnd = i & j;
if (currentAnd > maxAnd)
maxAnd = currentAnd;
}
}
cout << maxAnd << endl;
This might be not more optimized from efficiency perspective, but somewhat more readable.
var list = new[] {1, 2, 3, 4, 5};
var k = 2;
var combinations =
from item1 in list
from item2 in list
where
(item1 < item2) &&
(item1 & item2) < k
orderby item1 & item2 descending
select new {item1, item2};
Console
.WriteLine(combinations.First());
Turns out the solution can be drastically simplified (in terms of what we check, rather than readability). So, rather than providing ways to improve the code - I can offer a new solution to the original requirement
void Main()
{
var n = 2;
var k = 2;
//Best solution is for k - 1 (that is, B = k - 1, and then we check all possible As)
for (var i = k - 1; i > 0; i--)
{
int j;
int index = 1;
//The only possible A is when
//1. j <= n
//2. j contains all the same bits as i since we identify that `i` is the possible solution,
// and we are using bit-wise AND, we
//So, here were looping while the number is the same as i, continually flipping bits on
//Since we're shifting bits in, we can assume the first value != i is a solution, as we only care about j becoming too large
while ((j = (i | index)) == i && j <= n)
index = (index << 1) | 1;
// If j <= n, and it contains all the bits of i, and i <= k - 1, then we have a solution
if (j <= n)
{
Console.WriteLine($"i = {i}, j = {j}, Solution = {i & j}");
return;
}
}
if (n < 2 || k < 1)
Console.WriteLine("No solution");
else
Console.WriteLine($"i = 1, j = 2, Solution = 0");
}
This approach lets us solve inputs such as:
var n = 24827492;
var k = 2384972;
Almost as quickly as we can for low values.

Multiply elements in an array

Hi, I have an array : int [] num = new int[6]{1,2,2,1,1,2};
I want to multiply the value at element 0 with every other value, I then want to multiply the value at element 1 with the values at elements 2 through to the last element. Then multiply the value at element 2 with the values from 3 through to the end, and so on until I have iterated through the whole array.
My efforts thus far seem clumsy and verbose, so I was wondering if anyone could show me an elegant way of achieving my aim.
Many thanks.
You can go through the array backwards and do it in one pass and not repeat operations.
for (int i = num.Length - 2; i >= 0; i--)
{
num[i] *= num[i + 1];
}
Gives 8,8,4,2,2,2
Enumerable.Range(0,num.Length)
.Select(i => num.Skip(i).Aggregate(1, (a, b) => a * b))
Gives a sequence 8, 8, 4, 2, 2, 2. Is this what you meant?
This should do the job:
for (int i = 0; i < num.Length; i++)
{
// Multiply element i
for (int j = i+1; j < num.Length; j++)
{
num[i] *= num[j];
}
}
int[] num = new int[6] { 1, 2, 2, 1, 1, 2 };
int i = 0;
while (i < num.Length)
{
for (int j = i; j < num.Length;j++)
{
if((j+1)<num.Length)
num[i] = num[i] + num[j + 1];
}
Console.WriteLine(num[i]);
i++;
}

Categories