I was trying to brute force my way through the Grid Game problem on LeetCode without knowing what prefix sum was. And I thought my solution was good, not optimal but should get the job done. However, it failed on the 9th test case in a way that I don't understand.
Testcase
using solutions;
int[][] testCase = new int [2][];
testCase[0] = new int[] {20,3,20,17,2,12,15,17,4,15};
testCase[1] = new int[] {20,10,13,14,15,5,2,3,14,3};
SolutionV2 SLN = new SolutionV2();
Console.WriteLine(SLN.GridGame(testCase));
My Solution
namespace solutions;
public class SolutionV2 {
public long GridGame(int[][] grid)
{
long returnValue = 0;
long maxValue = 0;
int[] currentPosition = new int[] {0,0};
int maxCol = grid[0].GetLength(0);
Console.WriteLine("[{0}]", string.Join(", ", grid[0]));
Console.WriteLine("[{0}]", string.Join(", ", grid[1]));
for(int k=0;k<maxCol;k++) //find the highest path sum for the first robot
{
int sum = 0;
for(int i=0;i<maxCol;i++)
{
if(i<k)
{
sum += grid[0][i]; //sum up the first row until it is time to move down
}
else if(i==k)
{
sum += grid[0][i];
for(int j=i;j<maxCol;j++)
{
sum += grid[1][j];
}
if(sum>maxValue)
{
maxValue = sum;
}
break;
}
}
}
for(int k=0;k<maxCol;k++) //there has to be a better way to set the sum path to zero
{
int sum = 0;
for(int i=0;i<maxCol;i++)
{
if(i<k)
{
sum += grid[0][i]; //sum up the first row until it is time to move down
}
else if(i==k)
{
sum += grid[0][i];
for(int j=i;j<maxCol;j++)
{
sum += grid[1][j];
}
if(sum==maxValue) //found it, now set the path to zero
{
for(int a=0;a<=i;a++)
{
grid[0][a] = 0;
}
for(int a=i;a<maxCol;a++)
{
grid[1][a] = 0;
}
}
break;
}
}
}
Console.WriteLine("[{0}]", string.Join(", ", grid[0]));
Console.WriteLine("[{0}]", string.Join(", ", grid[1]));
for(int k=0;k<maxCol;k++) //find the highest path sum for the second robot
{
int sum = 0;
for(int i=0;i<maxCol;i++)
{
if(i<k)
{
sum += grid[0][i]; //sum up the first row until it is time to move down
}
else if(i==k)
{
sum += grid[0][i];
for(int j=i;j<maxCol;j++)
{
sum += grid[1][j];
}
if(sum>returnValue)
{
returnValue = sum;
}
break;
}
}
}
return returnValue;
}
}
The expected value for this particular test case was 63, which I don't understand where they got it from.
Related
To be requested 10 numbers from the user find the min and max number without using arrays. Strings should not be count and will give an error, however program will continue to calculate the min and max if some of the value has provided.
I solved the question but what I'm wondering to know if it is a good solution.
public static void MinMax()
{
double minSayi = 0;
double maxSayi = 0;
for (int i = 0; i < 10; i++)
{
Console.WriteLine("Sayı Giriniz: ");
bool isNumber = Double.TryParse(Console.ReadLine(), out double sayi);
if (isNumber)
{
if (i == 0)
{
minSayi = sayi;
maxSayi = sayi;
}
else
{
if (sayi < minSayi)
{
minSayi = sayi;
}
if (sayi > maxSayi)
{
maxSayi = sayi;
}
}
}
else
{
Console.WriteLine("Gecersiz sayi girdiniz.");
}
}
Console.WriteLine("*********************");
Console.WriteLine($"Min sayi: {minSayi}");
Console.WriteLine($"Max sayi: {maxSayi}");
Console.ReadLine();
}
I expect the output of (1, ... 10) => min = 1; max = 10;
I have created a piece of code to create an array of 100 elements which will randomize based on the numbers from a set array. However whenever I enter "y" I am looking the array to delete the last element and add a new random element to the start and move everything in between one to the right to allow for this. However at the moment it is completely changing the array every time I enter "y". Can anyone help with this?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace Rextester
{
public class Program
{
public static void Main(string[] args)
{
int[] values = { 1, 2, 3, 4, 5, 6 };
int Min = values[0];
int Max = values[5] + 1;
int w = 0 ;
int[] rndValues = new int[100];
Random rndNum = new Random();
Console.WriteLine("Random001 " + w);
for (int i = 0; i < rndValues.Length; i++)
{
rndValues[i] = rndNum.Next(Min, Max);
}
Console.WriteLine("Random " + w);
foreach(var item in rndValues)
{
Console.Write(item.ToString() + " ");
}
if (w==0)
{
Console.WriteLine(Environment.NewLine);
prob(rndValues, Min, Max,w);
Console.WriteLine(Environment.NewLine);
w++;
}
if (w>0)
{
while(true)
{
Console.WriteLine("To change elements in the array press y");
// read input
var s = Console.ReadLine();
if(s == "y")
{
//rndValues[99] = 0;
for(int i = 0; i == rndValues.Length; i++)
{
if (i != rndValues.Length)
{
rndValues[rndValues.Length-i] = rndValues[(rndValues.Length-i)-1];
}
else if (i == rndValues.Length)
{
rndValues[0] = rndNum.Next(Min, Max);
}
}
}
else
{
break;
}
prob(rndValues, Min, Max,w);
}
}
}
public static void prob(int[] rndValues, int Min, int Max, int w )
{
double[] count = new double[rndValues.Length];
//Loop through min to max and count the occurances
for (int i = Min; i <Max; i++)
{
for (int j = 0; j < rndValues.Length; j++)
{
if (rndValues[j] == i)
{
count[i] = count[i] + 1;
}
}
}
//For displaying output only
foreach(var item in rndValues)
{
Console.Write(item.ToString() + " ");
}
Console.WriteLine("W " + w);
for (int i = Min; i < Max; i++)
{
count[i] = (count[i] / rndValues.Length) * 100;
Console.WriteLine("Probability of the number " + i + " is " + count[i]);
}
}
}
}
Thanks.
I have temperature data stored in an array, but need to use that data for a while loop. What I have so far is:
public int BelowValueCounter(string tempValueIn)
{
int.TryParse(tempValueIn, out tempValueOut);
int checkValue = tempData[0];
while (tempValueOut > checkValue)
{
belowCounter++;
}
return belowCounter;
}
I just don't know how to increment tempData[0] so that it moves on to tempData[1] to repeat until the while loop condition is satisfied. Thanks!
If you want to keep the while loop, you need a variable for counting - here i - to get access to the desired array entry:
public int BelowValueCounter(string tempValueIn)
{
int.TryParse(tempValueIn, out tempValueOut);
int i = 0;
int checkValue = tempData[i];
while (tempValueOut > checkValue)
{
belowCounter++;
i++;
checkValue = tempData[i];
}
return belowCounter;
}
Or consider using a for loop:
public int BelowValueCounter(string tempValueIn)
{
int.TryParse(tempValueIn, out tempValueOut);
for (int i = 0; i < tempData.Length; i++)
{
if (tempValueOut > tempData[i])
{
belowCounter++;
continue;
}
break;
}
return belowCounter;
}
You can use a for loop, foreach loop, or a linq query.
void Main()
{
var counter = BelowValueCounter_UsingFor(46);
//var counter = BelowValueCounter_UsingLinq(46);
Console.WriteLine(counter);
}
decimal[] temperatures = new decimal[] { 40, 40, 45, 60, 70 };
public int BelowValueCounter_UsingLinq(decimal tempValueIn)
{
return temperatures.Count(a => a < tempValueIn);
}
public int BelowValueCounter_UsingFor(decimal tempValueIn)
{
int counter = 0;
for (int i = 0; i < temperatures.Length; i++)
{
if (temperatures[i] < tempValueIn)
counter++;
}
return counter;
}
I have a problem I need to solve using C#. There is an array of decimal numbers (representing quantities of an item received by a warehouse at different times). This array is already sorted in the order in which the quantities were received. I need to be able to find the earliest combination of quantities that sum up to a specified total quantity.
So for example, say I have some quantities that came in chronologically as follows [13, 6, 9, 8, 23, 18, 4] and say my total quantity to match is 23. Then I should be able to get [13, 6, 4] as the matching subset although [6, 9, 8] and [23] are also matching but not the earliest.
What would be the best approach/algorithm for this?
I have so far come up with a rather naive approach using recursion.
public class MatchSubset
{
private decimal[] qty = null;
private decimal matchSum = 0;
public int operations = 0;
public int[] matchedIndices = null;
public int matchCount = 0;
private bool SumUp(int i, int n, decimal sum)
{
operations++;
matchedIndices[matchCount++] = i;
sum += qty[i];
if (sum == matchSum)
return true;
if (i >= n - 1)
{
matchCount--;
return false;
}
if (SumUp(i + 1, n, sum))
return true;
sum -= qty[i];
matchCount--;
return SumUp(i + 1, n, sum);
}
public bool Match(decimal[] qty, decimal matchSum)
{
this.qty = qty;
this.matchSum = matchSum;
matchCount = 0;
matchedIndices = new int[qty.Count()];
return SumUp(0, qty.Count(), 0);
}
}
static void Main(string[] args)
{
var match = new MatchSubset();
int maxQtys = 20;
Random rand = new Random(DateTime.Now.Millisecond);
decimal[] qty = new decimal[maxQtys];
for (int i = 0; i < maxQtys - 2; i++)
qty[i] = rand.Next(1, 500);
qty[maxQtys - 2] = 99910;
qty[maxQtys - 1] = 77910;
DateTime t1 = DateTime.Now;
if (match.Match(qty, 177820))
{
Console.WriteLine(DateTime.Now.Subtract(t1).TotalMilliseconds);
Console.WriteLine("Operations: " + match.operations);
for (int i = 0; i < match.matchCount; i++)
{
Console.WriteLine(match.matchedIndices[i]);
}
}
}
The matching subset can be as short as one element and as long as the original set (containing all elements). But to test the worst case scenario, in my test program I am using an arbitrarily long set of which only the last two match the given number.
I see that with 20 numbers in the set, it calls the recursive function over a million times with a max recursion depth of 20. If I run into a set of 30 or more numbers in production, I am fearing it will consume a very long time.
Is there a way to further optimize this? Also, looking at the downvotes, is this the wrong place for such questions?
I was unable to end up with something revolutionary, so the presented solution is just a different implementation of the same brute force algorithm, with 2 optimizations. The first optimization is using iterative implementation rather than recursive. I don't think it is significant because you are more likely to end up with out of time rather than out of stack space, but still it's a good one in general and not hard to implement. The most significant is the second one. The idea is, during the "forward" step, anytime the current sum becomes greater than the target sum, to be able to skip checking the next items that have greater or equal value to the current item. Usually that's accomplished by first sorting the input set, which is not applicable in your case. However, while thinking how to overcome that limitation, I realized that all I need is to have for each item the index of the first next item which value is less than the item value, so I can just jump to that index until I hit the end.
Now, although in the worst case both implementations perform the same way, i.e. may not end in a reasonable time, in many practical scenarios the optimized variant is able to produce result very quickly while the original still doesn't end in a reasonable time. You can check the difference by playing with maxQtys and maxQty parameters.
Here is the implementation described, with test code:
using System;
using System.Diagnostics;
using System.Linq;
namespace Tests
{
class Program
{
private static void Match(decimal[] inputQty, decimal matchSum, out int[] matchedIndices, out int matchCount, out int operations)
{
matchedIndices = new int[inputQty.Length];
matchCount = 0;
operations = 0;
var nextLessQtyPos = new int[inputQty.Length];
for (int i = inputQty.Length - 1; i >= 0; i--)
{
var currentQty = inputQty[i];
int nextPos = i + 1;
while (nextPos < inputQty.Length)
{
var nextQty = inputQty[nextPos];
int compare = nextQty.CompareTo(currentQty);
if (compare < 0) break;
nextPos = nextLessQtyPos[nextPos];
if (compare == 0) break;
}
nextLessQtyPos[i] = nextPos;
}
decimal currentSum = 0;
for (int nextPos = 0; ;)
{
if (nextPos < inputQty.Length)
{
// Forward
operations++;
var nextSum = currentSum + inputQty[nextPos];
int compare = nextSum.CompareTo(matchSum);
if (compare < 0)
{
matchedIndices[matchCount++] = nextPos;
currentSum = nextSum;
nextPos++;
}
else if (compare > 0)
{
nextPos = nextLessQtyPos[nextPos];
}
else
{
// Found
matchedIndices[matchCount++] = nextPos;
break;
}
}
else
{
// Backward
if (matchCount == 0) break;
var lastPos = matchedIndices[--matchCount];
currentSum -= inputQty[lastPos];
nextPos = lastPos + 1;
}
}
}
public class MatchSubset
{
private decimal[] qty = null;
private decimal matchSum = 0;
public int operations = 0;
public int[] matchedIndices = null;
public int matchCount = 0;
private bool SumUp(int i, int n, decimal sum)
{
operations++;
matchedIndices[matchCount++] = i;
sum += qty[i];
if (sum == matchSum)
return true;
if (i >= n - 1)
{
matchCount--;
return false;
}
if (SumUp(i + 1, n, sum))
return true;
sum -= qty[i];
matchCount--;
return SumUp(i + 1, n, sum);
}
public bool Match(decimal[] qty, decimal matchSum)
{
this.qty = qty;
this.matchSum = matchSum;
matchCount = 0;
matchedIndices = new int[qty.Count()];
return SumUp(0, qty.Count(), 0);
}
}
static void Main(string[] args)
{
int maxQtys = 3000;
decimal matchQty = 177820;
var qty = new decimal[maxQtys];
int maxQty = (int)(0.5m * matchQty);
var random = new Random();
for (int i = 0; i < maxQtys - 2; i++)
qty[i] = random.Next(1, maxQty);
qty[maxQtys - 2] = 99910;
qty[maxQtys - 1] = 77910;
Console.WriteLine("Source: {" + string.Join(", ", qty.Select(v => v.ToString())) + "}");
Console.WriteLine("Target: {" + matchQty + "}");
int[] matchedIndices;
int matchCount;
int operations;
var sw = new Stopwatch();
Console.Write("#1 processing...");
sw.Restart();
Match(qty, matchQty, out matchedIndices, out matchCount, out operations);
sw.Stop();
ShowResult(matchedIndices, matchCount, operations, sw.Elapsed);
Console.Write("#2 processing...");
var match = new MatchSubset();
sw.Restart();
match.Match(qty, matchQty);
sw.Stop();
ShowResult(match.matchedIndices, match.matchCount, match.operations, sw.Elapsed);
Console.Write("Done.");
Console.ReadLine();
}
static void ShowResult(int[] matchedIndices, int matchCount, int operations, TimeSpan time)
{
Console.WriteLine();
Console.WriteLine("Time: " + time);
Console.WriteLine("Operations: " + operations);
if (matchCount == 0)
Console.WriteLine("No Match.");
else
Console.WriteLine("Match: {" + string.Join(", ", Enumerable.Range(0, matchCount).Select(i => matchedIndices[i].ToString())) + "}");
}
}
}
Is the following 0-1 Knapsack problem solvable:
'float' positive values and
'float' weights (can be positive or negative)
'float' capacity of the knapsack > 0
I have on average < 10 items, so I'm thinking of using a brute force implementation. However, I was wondering if there is a better way of doing it.
This is a relatively simple binary program.
I'd suggest brute force with pruning. If at any time you exceed the allowable weight, you don't need to try combinations of additional items, you can discard the whole tree.
Oh wait, you have negative weights? Include all negative weights always, then proceed as above for the positive weights. Or do the negative weight items also have negative value?
Include all negative weight items with positive value. Exclude all items with positive weight and negative value.
For negative weight items with negative value, subtract their weight (increasing the knapsack capavity) and use a pseudo-item which represents not taking that item. The pseudo-item will have positive weight and value. Proceed by brute force with pruning.
class Knapsack
{
double bestValue;
bool[] bestItems;
double[] itemValues;
double[] itemWeights;
double weightLimit;
void SolveRecursive( bool[] chosen, int depth, double currentWeight, double currentValue, double remainingValue )
{
if (currentWeight > weightLimit) return;
if (currentValue + remainingValue < bestValue) return;
if (depth == chosen.Length) {
bestValue = currentValue;
System.Array.Copy(chosen, bestItems, chosen.Length);
return;
}
remainingValue -= itemValues[depth];
chosen[depth] = false;
SolveRecursive(chosen, depth+1, currentWeight, currentValue, remainingValue);
chosen[depth] = true;
currentWeight += itemWeights[depth];
currentValue += itemValues[depth];
SolveRecursive(chosen, depth+1, currentWeight, currentValue, remainingValue);
}
public bool[] Solve()
{
var chosen = new bool[itemWeights.Length];
bestItems = new bool[itemWeights.Length];
bestValue = 0.0;
double totalValue = 0.0;
foreach (var v in itemValues) totalValue += v;
SolveRecursive(chosen, 0, 0.0, 0.0, totalValue);
return bestItems;
}
}
Yeah, brute force it. This is an NP-Complete problem, but that shouldn't matter because you will have less than 10 items. Brute forcing won't be problematic.
var size = 10;
var capacity = 0;
var permutations = 1024;
var repeat = 10000;
// Generate items
float[] items = new float[size];
float[] weights = new float[size];
Random rand = new Random();
for (int i = 0; i < size; i++)
{
items[i] = (float)rand.NextDouble();
weights[i] = (float)rand.NextDouble();
if (rand.Next(2) == 1)
{
weights[i] *= -1;
}
}
// solution
int bestPosition= -1;
Stopwatch sw = new Stopwatch();
sw.Start();
// for perf testing
//for (int r = 0; r < repeat; r++)
{
var bestValue = 0d;
// solve
for (int i = 0; i < permutations; i++)
{
var total = 0d;
var weight = 0d;
for (int j = 0; j < size; j++)
{
if (((i >> j) & 1) == 1)
{
total += items[j];
weight += weights[j];
}
}
if (weight <= capacity && total > bestValue)
{
bestPosition = i;
bestValue = total;
}
}
}
sw.Stop();
sw.Elapsed.ToString();
If you can only have positive values then every item with a negative weight must go in.
Then I guess you could calculate Value/Weight Ratio, and brute force the remaining combinations based on that order, once you get one that fits you can skip the rest.
The problem may be that the grading and sorting is actually more expensive than just doing all the calculations.
There will obviously be a different breakeven point based on the size and distribution of the set.
public class KnapSackSolver {
public static void main(String[] args) {
int N = Integer.parseInt(args[0]); // number of items
int W = Integer.parseInt(args[1]); // maximum weight of knapsack
int[] profit = new int[N + 1];
int[] weight = new int[N + 1];
// generate random instance, items 1..N
for (int n = 1; n <= N; n++) {
profit[n] = (int) (Math.random() * 1000);
weight[n] = (int) (Math.random() * W);
}
// opt[n][w] = max profit of packing items 1..n with weight limit w
// sol[n][w] = does opt solution to pack items 1..n with weight limit w
// include item n?
int[][] opt = new int[N + 1][W + 1];
boolean[][] sol = new boolean[N + 1][W + 1];
for (int n = 1; n <= N; n++) {
for (int w = 1; w <= W; w++) {
// don't take item n
int option1 = opt[n - 1][w];
// take item n
int option2 = Integer.MIN_VALUE;
if (weight[n] <= w)
option2 = profit[n] + opt[n - 1][w - weight[n]];
// select better of two options
opt[n][w] = Math.max(option1, option2);
sol[n][w] = (option2 > option1);
}
}
// determine which items to take
boolean[] take = new boolean[N + 1];
for (int n = N, w = W; n > 0; n--) {
if (sol[n][w]) {
take[n] = true;
w = w - weight[n];
} else {
take[n] = false;
}
}
// print results
System.out.println("item" + "\t" + "profit" + "\t" + "weight" + "\t"
+ "take");
for (int n = 1; n <= N; n++) {
System.out.println(n + "\t" + profit[n] + "\t" + weight[n] + "\t"
+ take[n]);
}
}
}
import java.util.*;
class Main{
static int max(inta,int b)
{
if(a>b)
return a;
else
return b;
}
public static void main(String args[])
{
int n,i,cap,j,t=2,w;
Scanner sc=new Scanner(System.in);
System.out.println("Enter the number of values ");
n=sc.nextInt();
int solution[]=new int[n];
System.out.println("Enter the capacity of the knapsack :- ");
cap=sc.nextInt();
int v[]=new int[n+1];
int wt[]=new int[n+1];
System.out.println("Enter the values ");
for(i=1;i<=n;i++)
{
v[i]=sc.nextInt();
}
System.out.println("Enter the weights ");
for(i=1;i<=n;i++)
{
wt[i]=sc.nextInt();
}
int knapsack[][]=new int[n+2][cap+1];
for(i=1;i<n+2;i++)
{
for(j=1;j<n+1;j++)
{
knapsack[i][j]=0;
}
}
/*for(i=1;i<n+2;i++)
{
for(j=wt[1]+1;j<cap+2;j++)
{
knapsack[i][j]=v[1];
}
}*/
int k;
for(i=1;i<n+1;i++)
{
for(j=1;j<cap+1;j++)
{
/*if(i==1||j==1)
{
knapsack[i][j]=0;
}*/
if(wt[i]>j)
{
knapsack[i][j]=knapsack[i-1][j];
}
else
{
knapsack[i][j]=max(knapsack[i-1][j],v[i]+knapsack[i-1][j-wt[i]]);
}
}
}
//for displaying the knapsack
for(i=0;i<n+1;i++)
{
for(j=0;j<cap+1;j++)
{
System.out.print(knapsack[i][j]+" ");
}
System.out.print("\n");
}
w=cap;k=n-1;
j=cap;
for(i=n;i>0;i--)
{
if(knapsack[i][j]!=knapsack[i-1][j])
{
j=w-wt[i];
w=j;
solution[k]=1;
System.out.println("k="+k);
k--;
}
else
{
solution[k]=0;
k--;
}
}
System.out.println("Solution for given knapsack is :- ");
for(i=0;i<n;i++)
{
System.out.print(solution[i]+", ");
}
System.out.print(" => "+knapsack[n][cap]);
}
}
This can be solved using Dynamic Programming. Below code can help you solve the 0/1 Knapsack problem using Dynamic Programming.
internal class knapsackProblem
{
private int[] weight;
private int[] profit;
private int capacity;
private int itemCount;
private int[,] data;
internal void GetMaxProfit()
{
ItemDetails();
data = new int[itemCount, capacity + 1];
for (int i = 1; i < itemCount; i++)
{
for (int j = 1; j < capacity + 1; j++)
{
int q = j - weight[i] >= 0 ? data[i - 1, j - weight[i]] + profit[i] : 0;
if (data[i - 1, j] > q)
{
data[i, j] = data[i - 1, j];
}
else
{
data[i, j] = q;
}
}
}
Console.WriteLine($"\nMax profit can be made : {data[itemCount-1, capacity]}");
IncludedItems();
}
private void ItemDetails()
{
Console.Write("\nEnter the count of items to be inserted : ");
itemCount = Convert.ToInt32(Console.ReadLine()) + 1;
Console.WriteLine();
weight = new int[itemCount];
profit = new int[itemCount];
for (int i = 1; i < itemCount; i++)
{
Console.Write($"Enter weight of item {i} : ");
weight[i] = Convert.ToInt32(Console.ReadLine());
Console.Write($"Enter the profit on the item {i} : ");
profit[i] = Convert.ToInt32(Console.ReadLine());
Console.WriteLine();
}
Console.Write("\nEnter the capacity of the knapsack : ");
capacity = Convert.ToInt32(Console.ReadLine());
}
private void IncludedItems()
{
int i = itemCount - 1;
int j = capacity;
while(i > 0)
{
if(data[i, j] == data[i - 1, j])
{
Console.WriteLine($"Item {i} : Not included");
i--;
}
else
{
Console.WriteLine($"Item {i} : Included");
j = j - weight[i];
i--;
}
}
}
}