Multiknapsack algorithm - out of collection while trying to remove object - c#

I've encountered the problem while working on my multiknapsack solver.
The program is working well on one knapsack but when it comes to multiple knaps there are some problems.
Problem: The items aren't removed from collection. I know that I need to do this, because for the second knapsack its iterating again through the same objects - so the maximized val is the same...
private void Knapsack()
{
List<Plecak> descendingKanps = _plecakList.OrderByDescending(o => o.W).ToList(); // List of configured Kanpsacks in descending order
List<Produkt> descendingProducts = _produktList.OrderByDescending(o => o.cena).ToList(); // List of products to pack in descending order
int N = descendingProducts.Count; //number of items in product list
double maxVal = 0; // accumulated value of one knapsack
foreach (Plecak p in descendingKanps) // for every knapsack...
{
double[,] V = new double[N + 1, (int)p.W + 1]; //array that stores best option (the value of item)
for (int c = 0; c <= p.W; c++) //since its a 0-1 MKP problem so initialize whole array with zeroes
{
V[0, c] = 0;
}
for (int r = 0; r <= N; r++)
{
V[r, 0] = 0;
}
for (int i = 1; i <= N; i++) // constraint of items count
{
for (int wt = 1; wt <= p.W; wt++) //the constraint of weight
{
if (descendingProducts[i - 1].waga < wt + 1) // if weight of the product is less than constraint, so it can be added...
V[i, wt] = Math.Max(descendingProducts[i - 1].cena + V[i - 1, wt - descendingProducts[i - 1].waga], V[i - 1, wt]); // find best solution and add the value to the Value array, comapre the value with the value form previous row
else
V[i, wt] = V[i - 1, wt]; // keep 0, or last best solution
maxVal = V[i, wt]; // assign to variable
}
}
summary.Items.Add("maximum val for knapsack: " + p.nazwa + " is: " + maxVal); // print out the value of knapsack
}
}

This will hopefully turn into an answer, but for now it is a question.
In your code you have this:
for (int c = 0; c <= p.W; c++) //since its a 0-1 MKP problem so initialize whole array with zeroes
{
V[0, c] = 0;
}
for (int r = 0; r <= N; r++)
{
V[r, 0] = 0;
}
You say that you "initialize whole array with zeroes". The above code will do this to an array:
0 0 0 0 0
0 1 1 1 1
0 1 1 1 1
0 1 1 1 1
You'll only ever reach the first column and the top row. If all places in the array should be changed to 0, then this is the correct approach:
for (int r = 0; r <= N; r++)
{
for (int c = 0; c <= p.W; c++)
{
V[r, c] = 0;
}
}
I hope this input can be of help.

Related

Print all points in an infinite grid of n dimensions

I can not have infinite points stored in the computer, but what I mean by that is the max value of Int64 (long).
I could use a nested loop, but that would take an eternity to go to the next line, so I found another way.
All the points whose x and y values add upto n are on a diagonal.
(0,0) - 0
(1,0),(0,1) - 1
(2,0),(1,1),(0,2) - 2
(all of these are diagonals)
So we could iterate through all values of n, from 0 to max value of long, that would give us all the points on all the diagonals.
So I wrote the code to do this.
public void Main()
{
for(long i = 0; i < Int64.MaxValue; i++)
{
long[] a = new long[(i + 1)];
long[] b = new long[(i + 1)];
for(long j = 0; j <= i; j++)
{
a[j] = j;
b[j] = (i - a[j]);
}
f(a,b);
}
}
public void f(long[] a, long[] b)
{
string toPrint = "";
for(int i = 0; i < a.Length; i++)
{
toPrint += "(" + a[i] + "," + b[i] + "),";
}
Console.Write(toPrint + "\n\n");
}
It does the job for a grid of 2 dimensions, but I want it to work for n dimensions, the same idea applies

C# Splitting a multidimensional array

So I have been searching for an answer for this for about an hour now and I was unable to find one so I'm going to try my luck here.
The problem:
I have a 3 dimensional Array that contains Containers. This array is for an algoritm for placing containers on a cargoship. The array consists of Length, width and height. I am trying to split the array at the middle of the width.
The only solution I have been able to sort of make work is making 2, 3 dimensional arrays and then using 6 for loops to copy the big array:
Container[,,] leftSideOfShip = new Container[ship.length, ((ship.width) / 2), ship.height];
Container[,,] rightSideOfShip = new Container[ship.length, ((ship.width) / 2), ship.height];
for(int a = 0; a < ship.length; a++)
{
for(int b = 0; b < ship.width/2; b++)
{
for(int c = 0; c < ship.height; c++)
{
if(ship.position[a,b,c] != null)
{
leftSideOfShip[a, b, c] = ship.position[a, b, c];
}
}
}
}
for (int d = 0; d < ship.length; d++)
{
for (int e = ship.width/2; e < ship.width; e++)
{
for (int f = 0; f < ship.height; f++)
{
if(ship.position[d,e,f] != null)
{
rightSideOfShip[d, e, f] = ship.position[d, e, f];
}
}
}
}
The 3 for loops for the leftSideOfShip work as expected but the second one gives an indexOutOfRangeException.
Is there a better way to split this and if so how?
First of all, you need to be mindful of how you round side width in case the width of the ship is odd. For example, you can always assume, that the left side is wider in case the width of the ship is odd, something like that:
int leftSideWidth = ship.width % 2 == 0 ? ship.width / 2 : (ship.width / 2) + 1;
int rightSideWidth = ship.width / 2;
Second of all, you have an error in your second loop block:
since you are looping for (int e = ship.width/2; e < ship.width; e++) e is greater than second dimension of rightSideOfShip array.
Full solution will look something like this:
Container[,,] leftSideOfShip = new Container[ship.length, leftSideWidth, ship.height];
Container[,,] rightSideOfShip = new Container[ship.length, rightSideWidth, ship.height];
for (int i = 0; i < ship.length; i++)
{
for (int j = 0; j < ship.width; j++)
{
for (int k = 0; k < ship.height; k++)
{
if (j < leftSideWidth)
{
leftSideOfShip[i, j, k] = ship.position[i, j, k];
}
else
{
rightSideOfShip[i, j - leftSideWidth, k] = ship.position[i, j, k];
}
}
}
}

How would you create n nested loops for math?

So, I am trying to wrap my head around understanding how you can use a variable to denote how many times a loop is nested.
Here is an example I write up to simulate the output of dimensions = 4:
static void Main(string[] args)
{
int dimensions = 4; // e.g. for (1, 2, 3, 4), dimensions = 4
Console.WriteLine($"{addNumbers(dimensions)}");
Console.ReadKey();
}
static long addNumbers(int dimensions)
{
long number = 0;
// hard coded to be dimensions = 4
for (int h = 0; h <= dimensions; h++)
for (int i = 0; i <= dimensions; i++)
for (int j = 0; j <= dimensions; j++)
for (int k = 0; k <= dimensions; k++)
number += h + i + j + k; // just some random math
return number;
}
This will present the expected output of:
5000
So to readdress the problem, how can I code to allow this for n dimensions? Thanks for your help!
For arbitrary n dimensions you can loop with a help of array int[] address which represents n dimensions:
static long addNumbers(int dimensions) {
int[] address = new int[dimensions];
// size of each dimension; not necessary equals to dimensions
// + 1 : in your code, int the loops you have i <= dimensions, j <= dimensions etc.
int size = dimensions + 1;
long number = 0;
do {
//TODO: some math here
// i == address[0]; j = address[1]; ... etc.
number += address.Sum();
// next address: adding 1 to array
for (int i = 0; i < address.Length; ++i) {
if (address[i] >= size - 1)
address[i] = 0;
else {
address[i] += 1;
break;
}
}
}
while (!address.All(index => index == 0)); // all 0 address - items're exhausted
return number;
}
Finally, let's add some Linq to look at the results:
int upTo = 5;
string report = string.Join(Environment.NewLine, Enumerable
.Range(1, upTo)
.Select(i => $"{i} -> {addNumbers(i),6}"));
Console.Write(report);
Outcome:
1 -> 1
2 -> 18
3 -> 288
4 -> 5000 // <- We've got it: 5000 for 4 dimensions
5 -> 97200

Random number in loop

My function return the same number sequence.
When i give on input list with first list[0] all 0 and second list[1] all 1, i get on the output list e.g:
1 1 1 1 0 1 1
1 1 1 1 0 1 1
And all the time generate sequence on the output is the same.
I mean temp[0] and temp[1] have the same sequence
public List<float[][][]> rozmnarzanie(List<nur> list,Random dnd)
{
float[][][] ftemp=net.wagi;
List<float[][][]> temp = new List<float[][][]>();
for (int i = 0; i < 2; i++)
{
for (int a = 0; a < net.wagi.Length; a++)
{
for (int j = 0; j < net.wagi[a].Length; j++)
{
for (int k = 0; k < net.wagi[a][j].Length; k++)
{
if(dnd.Next(0,100)<=50)
{
ftemp[a][j][k] = list[0].listawagi[a][j][k];
}
else
{
ftemp[a][j][k] = list[1].listawagi[a][j][k];
}
}
}
}
temp.Add(ftemp);
}
return temp;
}
I mean temp[0] and temp[1] have the same sequence
Correct. You add the same array twice, temp[0] and temp[1] are both references to the same location in memory. What you see are the results of the last run. The same result will show up in net.wagi .
Your question isn't about random numbers but about arrays being reference types.
I don't know what net.wagi is but the solution could look something like:
//float[][][] ftemp=net.wagi;
List<float[][][]> temp = new List<float[][][]>();
for (int i = 0; i < 2; i++)
{
float[][][] ftemp = new float[a][b][c]; // pseudo code
...
temp.Add(ftemp);
}
You figure out the a, b and c.

indexOutofRange BubbleSort when using inputbox

Its been bugging me for hours because it is always returning 0 at numbers[i] and I cant figure out the problem. code worked for a different program but I had to change it so it could have a custom array size and that's when everything went wrong.
any help would be great.
Thanks in advance.
int[] numbers = new int[Convert.ToInt16(TxtArray.Text)];
int j = 0;
for (j = numbers.Length; j >= 0; j--)
{
int i = 0;
for (i = 0; i <= j - 1; i++)
{
string NumbersInput = Microsoft.VisualBasic.Interaction.InputBox("Enter Numbers to be sorted",
"Numbers Input", "", -1, -1);
numbers[i] = Convert.ToInt16(NumbersInput);
//returns 0 in if statement
if (numbers[i] < numbers[i + 1])
{
int intTemp = 0;
intTemp = numbers[i];
numbers[i] = numbers[i + 1];
numbers[i + 1] = intTemp;
}
}
}
for (int i = 0; i < numbers.Length; i++)
{
LstNumbers.Items.Add(numbers[i]);
}
private void button1_Click(object sender, EventArgs e)
{
int sizeOfArrayInt = Convert.ToInt32(arraySize.Text);
int[] array = new int[sizeOfArrayInt];
string numbers = arrayValues.Text;
string[] numbersSplit = numbers.Split(',');
int count = 0;
foreach (string character in numbersSplit)
{
int value;
bool parse = Int32.TryParse(character, out value);
if (value != null)
{
array[count] = value;
}
count++;
}
array = this.SortArray(array);
foreach (int item in array)
{
this.listBox.Items.Add(item);
}
}
private int[] SortArray(int[] arrayToSort)
{
//int[] sortedArray = new int[arrayToSort.Length];
int count = arrayToSort.Length;
for (int j = count; j >= 0; j--)
{
int i = 0;
for (i = 0; i <= j - 2; i++)
{
if (arrayToSort[i] < arrayToSort[i + 1])
{
int intTemp = 0;
intTemp = arrayToSort[i];
arrayToSort[i] = arrayToSort[i + 1];
arrayToSort[i + 1] = intTemp;
}
}
}
return arrayToSort;
}
strong text
This I got to work as a Windows Form and the output displays in the list box as each array item or individual i iteration over the array. Of course there is no error checking. Hope that helps.
Setting aside the strangeness of how you are working with text boxes, your problem with throwing an exception would happen even without them because it lies here, in your inner loop:
for (i = 0; i <= j - 1; i++)
Suppose that numbers.Length == 2. This means that j == 2. So on the first time through the outer loop, you hit the inner loop with these conditions. The first time through, i == 0. You get to the if statement:
if (numbers[i] < numbers[i + 1])
numbers[0] exists, and numbers[1] exists, so this iteration goes through fine and i is incremented.
Now i == 1. Now the loop checks its boundary condition. i <= j - 1 == true, so the loop continues. Now when you hit that if statement, it tries to access numbers[i + 1], i.e., numbers[2], which does not exist, throwing an IndexOutOfRangeException.
Edit: Came back and realized that I left out the solution (to the exception, anyway). For the bubble sort to work, your inner loop's boundary condition should be i <= j - 2, because j's initial value is == numbers.Length, which is not zero-based, while array indexes are.
Second Edit: Note that just using a List won't actually solve this problem. You have to use the right boundary condition. Trying to access list[list.Count()] will throw an ArgumentOutOfRangeException. Just because a List will dynamically resize doesn't mean that it will somehow let you access items that don't exist. You should always take time to check your boundary conditions, no matter what data structure you use.

Categories

Resources