Cheapest cost through an array - c#

Question
Given an array of length[N] you must start at array[0] and traverse through to the end. You are allowed to to move one position or two i.e. array[0] -> array[1] or array[0] -> array[2] depending on which sum of numbers are lower. This will repeat all the way to the end and must include array[N].
[1, 10, 3, 8, 4]
Cheapest way to navigate is = 8 via array[0] + array[2] + array[4]
My current solution:
int totalCost = 0
totalCost += array[0]
int i = 1;
while (i < array.length)
{
if (i + 1 < array.length)
{
int sum1 = totalCost + array[i];
int sum2 = totalCost + array[i + 1];
if (sum1 < sum2)
{
totalCost += array[i];
i++;
}
else
{
totalCost += array[i + 1];
i += 2;
}
}
else
{
totalCost += array[i];
i++;
}
}
This seems to work for most arrays...the issue comes into play where if an early jump results in a bigger number but allows for a better jump further through the array ultimately resulting in a lower number. I have no clue how to approach that.

var c = new List<int>();
for (int i = 0; i < a.Length - 1;)
{
c.Add(i);
if (i < a.Length - 2 && a[i + 2] < a[i + 1])
i += 2;
else
i += 1;
}
c.Add(a[a.Length - 1]);

Your approach is not working, because you try to decide on the next move when you are at some element. Point is, you can't generally decide on your next move until you know all element values up to the second element from the end of array.
Not only in computer science but generally it is easier to look into the past and learn than to look into the future and predict. So whenever a problem or sub-problem can be solved from historic data, don't try to solve it with future expectations.
Now, lets look how this can be applied to your problem.
If you are at position i in your array, what you do is trying to predict the right way by looking at the possible next steps and deciding on one of them, this is not working reliably. So lets instead suppose you are at position i and you don't want to know where to go next but instead you ask "What is the best (cost efficient) way to reach the current position and how much does it cost?".
For the first position i=0, this is trivial. You reach this position by starting the algorithm and the cost equals the value of a[0].
For the second position i=1, it is also trivial. You can move in steps of 1 (small step) or 2 (big step), but in this specific case, only a small step is possible, so you reach i=1 by comming from position i=0 and the cost equals the cost of reaching i=0 plus the value of position i=1.
For all following positions i>1, a decision needs to be made, whether the current position is reached by going a small step or a big step. If the current position is reached by a small step, its cost is calculated as the cost of reaching i-1 plus the value of position i. Other case, if the current position is reached by a big step, its cost is calculated as the cost of reaching i-2 plus the value of position i. In order to reach position i with the lowest cost, decide between small and big step by comparing their associated cost and chosing the minimum.
When the end of the array is reached, the cost and steps of reaching each position will be computed and the cost of reaching the last position can be returned as a result.
If you only need the minimum cost and not the actual path, then the following should work (c-related pseudo code):
costs[array.size] = { 0 };
for (i = 0; i < array.size; ++i)
{
if (i > 1) costs[i] = array[i] + min(costs[i-1], costs[i-2]);
else if (i > 0) costs[i] = array[i] + costs[i-1];
else costs[i] = array[i];
}
result = costs[array.size - 1];
It basically says: reaching a point i can be done by comming from the previous point or from 2 points before. If the cost for the two previous points is already computed, the decision is as easy as taking the minimum of the two previous point costs and adding the current point cost.
Instead of an array with all sub-costs, you could even do with a total of 3 variables (discard sub-costs that represent indices below i-2), but then the path can't be re-constructed from the sub-costs.

I ignored the possibility of future sums being effected by earlier choices. I agree that is at some level of AI.
Solution I revised to.
int total = 0;
cost += array[0];
int i = 0;
while (i < array.Length - 1)
{
if ((array[i+1] + total) < array[i+2] + total) && (i != array.Length - 3))
{
total += array[i + 1];
i++;
}
else
{
total += array[i + 2];
i += 2;
}
}
I had to add the second to last element check because if the iterator landed on 2nd to last, there was no reason to check which one was lower as I had to pick the last one regardless.

Related

Fastest way to check each neighbor in 2D array

I am working on a random dungeon generator just for fun / as a side project to learn some new things. I have written a function that returns an integer hash value for any given cell, which gives you information about what type of gameobject it should be. i.e. if it is a wall, what direction to face, is it a corner, etc. Here is what the function currently looks like.
private int CellHashValue(int xIndex, int yIndex, char centerTile)
{
int hashValue = 0;
if (dungeon2DArray[xIndex - 1, yIndex + 1] == centerTile)
{
hashValue += 1;
}
if (dungeon2DArray[xIndex, yIndex + 1] == centerTile)
{
hashValue += 2;
}
if (dungeon2DArray[xIndex + 1, yIndex + 1] == centerTile)
{
hashValue += 4;
}
if (dungeon2DArray[xIndex - 1, yIndex] == centerTile)
{
hashValue += 8;
}
if (dungeon2DArray[xIndex + 1, yIndex] == centerTile)
{
hashValue += 16;
}
if (dungeon2DArray[xIndex - 1, yIndex - 1] == centerTile)
{
hashValue += 32;
}
if (dungeon2DArray[xIndex, yIndex - 1] == centerTile)
{
hashValue += 64;
}
if (dungeon2DArray[xIndex + 1, yIndex - 1] == centerTile)
{
hashValue += 128;
}
return hashValue;
}
My question is, is there a more efficient and faster way to do these checks that perhaps I am not thinking of? The dungeon array ranges in size from 100x100 to 1000x1000, though the function is not called on each cell. I have a separate List that contains rooms and there start and end indexes for each direction that I iterate over to instantiate objects.
What you're doing is essentially applying a form of convolution. Without more context as to how your method is being called or how you're using the returned hash value, what you're doing seems to be close to the most efficient way to iterate a 3x3 grid. Assuming your dungeon2dArray is a char[][] and is global, this is what I believe to be a bit clearer and more concise (you'll have to adjust how to interpret the resulting sum based on the order of iteration).
private int CellHashValue(int x, int y) {
int hashSum = 0; // Hash sum to return
int hashValue = 1; // Increases as power of 2 (1,2,4,8,...128)
char centerTile = dungeon2DArray[x, y]; // Cache center tile
for (int r = -1; r <= 1; r++) {
for (int c = -1; c <= 1; c++) {
if (r == 0 && c == 0) continue; // Skip center tile
if (dungeon2DArray[x + c, y + r] == centerTile) {
hashSum += hashValue;
}
hashValue *= 2; // Next power of two
//could also bit shift here instead
// hashValue <<= 1
}
}
return hashSum;
}
Note: This method doesn't do any boundary checking, so if x or y index is along edge, indices will fail.
Each of the array accesses is O(1) and iterating over your entire dungeon array is O(n^2), so the only way to get better efficiency would be to combine per cell methods calls, but this is still only a constant factor, so not really more efficient, but depending on the calculation could boost performance a little bit.
Since you are using an array to build the map then the access time is constant due to direct access. Thus, the process of checking each array index is fast.
There are several minor things to speed up the function.
Return the hashValue within the corresponding if statement. This will remove a few lines of code.
By removing the hashValue variable and returning a hard-coded value, a variable initialization will be removed from the process. This is more significant than it may seem. To create and remove an object takes time, lots of time when at scale.
xIndex and yIndex can be made global to the object. Be careful implementing this idea. Since xIndex and yIndex are not changing while checking for specific conditions then they can be made global within the object. This reduces the number of parameters passed in. Since Java does not pass by reference then an object of equal size is created and passed into the function. A simple int won't impact the speed much but if you have an object that contains many variables then more time is needed to build another object of equal value.
Each check can be moved to a separate function. This primarily helps with readability and debugging later on. There are some speed advantages but they're project dependent. By observing how objects are initialized/manipulated then certain conditions can typically be forced to be true. When logic doesn't need to be checked and conclusions can be reached without checks, then less time is needed.
Just a few ideas. If you have some time to research, the 2nd and 3rd points use concepts from low latency/high frequency. Also, be aware that some of these concepts are not thought of as best practice.

Genetic Algorithm stops mutating

I'm currently trying to make my genetic algorithm "generate" or "evolve" towards an given word. The problem is, that it never fully reaches this word, it stops at an too high fitness score, even if it should continue mutating.
Heres an example:
User input = "HelloWorld"
After 500 generations = "XelgoWorfd"
And I have no clue why it won't continue mutating. Normally it just should resume with changing randomly some chars in the string.
So I would be very glad about some help.
Here's an basic step by step explanation:
Create 20 Chromosomes with fully randomized strings
Calculate the fitness score compared to the goal word.
(Counting Ascii ids differences)
Mate the two Chromosomes with the best score.
Mutate some of the Chromosomes randomly (change random string chars)
Kill 90% of the weak population and replace it with elite chromosomes (The chromosomes with the currently best fitness score).
Repeat everything.
So here the most important methods of my algorithm:
public Chromoson[] mate(string gene) {
Console.WriteLine("[MATING] In Progress : "+gens+" "+gene);
int pivot = (int)Math.Round((double)gens.Length / 2) - 1;
string child1 = this.gens.Substring(0, pivot) + gene.Substring(pivot);
string child2 = gene.Substring(0, pivot) + this.gens.Substring(pivot);
Chromoson[] list = new Chromoson[2];
list[0] = new Chromoson(child1);
list[1] = new Chromoson(child2);
Console.WriteLine("[MATING] Pivot : "+pivot);
Console.WriteLine("[MATING] Children : "+child1+" "+child2);
return list;
}
public void mutate(float chance, int possiblyChanges) {
if (random.Next(0,101) <= chance) return;
int changes = random.Next(0, possiblyChanges + 1);
//int index = (int) Math.Floor((double)random.Next() * this.gens.Length);
for (int i = 0; i < changes; i++) {
int index = random.Next(0, 13);
StringBuilder builder = new StringBuilder(gens);
int upOrDown = random.Next(0, 101);
if (upOrDown <= 50 && (int)builder[index] > 0 && chars.Contains(Convert.ToChar(builder[index] - 1)))
builder[index] = Convert.ToChar(builder[index] - 1);
else if (upOrDown >= 50 && (int)builder[index] < 127 && chars.Contains(Convert.ToChar(builder[index] + 1)))
builder[index] = Convert.ToChar(builder[index] + 1);
else
mutate(chance, possiblyChanges);
gens = builder.ToString();
}
Console.WriteLine("[MUTATING] In Progress");
}
public void calculateCost(string otherGens)
{
int total = 0;
for (int i = 0; i < gens.Length; i++)
{
total += (((int)gens[i] - (int)otherGens[i]) * ((int)gens[i] - (int)otherGens[i])) * (i*i);
}
Console.WriteLine("[CALCULATING] Costs : " + total);
this.cost = total;
}
Something is completely off in your timesteps:
Create 20 Chromosomes with fully randomized strings. Seems okay.
Calculate the fitness score compared to the goal word. (Counting Ascii ids differences). Seems okay.
Mate the two Chromosomes with the best score. What? Your only breeding the two fittest chromosomes to create the new population? That means you will have a population that is nearly completely similar. Breedfitness proportionally, so all genomes have a chance to have an offspring
Mutate some of the Chromosomes randomly (change random string chars)
Kill 90% of the weak population and replace it with elite chromosomes (The chromosomes with the currently best fitness score). You kill 90%? So basically, you're keeping the 2 best genomes every iteration and then replacing the other 18 with step 1? What you want is to keep the 2 fittest at step 3, and create the other 18 individuals by breeding.
Repeat everything.
So change your steps to:
INIT. Initialise population, create 20 random chromosomes
Calculate score for each chromsome
Save the two fittest chromosomes to the next population (aka elitism), getthe other 18 needed individuals by breeding fitness proportionally
Mutate the chromsomes with a certain chance
Repeat
Do not create random individuals every round. This turns your algorithm into a random search.
Your mutate and calculateCost functions are weird. In particular, mutate() looks designed to get trapped in local minimas. Any mutation up or down will be worse than the elites (which are probably identical so crossover changes nothing). Use a different mutate: Pick a random index and change it completely. Also remove i*i from cost().

How can i make the FOR to loop backward ? Getting some errors

for (int i = uids.Count; i > 0; i--)
{
counting += 1;
if (counting == 30)
break;
string currentUidOnServer = uids[i - 1];
if (!seenUids.Contains(currentUidOnServer))
{
OpenPop.Mime.Message unseenMessage = client.GetMessage(i + 1);
newMessages.Add(unseenMessage);
seenUids.Add(currentUidOnServer);
allMessages.Add(unseenMessage);
int nProgress = (uids.Count - i + 1) * 100 / uids.Count;
backgroundWorker1.ReportProgress(nProgress, client.GetMessageCount().ToString() + "/" + i);
}
}
The variable uids contain 7038 items.
I want to report to the backgroundworker progresschanged event.
And it does reporting but it did backward started from 7038 and 100%
And i want it to report from 0% to 100% so i changed the FOR to
for (int i = uids.Count; i > 0; i--)
It was
for (int i = 0; i < uids.Count; i++)
The first error out of index exception was on the line
string currentUidOnServer = uids[i - 1];
So i changed it to [i - 1]
Now i'm getting exception on the line
OpenPop.Mime.Message unseenMessage = client.GetMessage(i + 1);
Since 7038 + 1 not exist.
So i messed it all.
How this two lines i have/had the exceptions should be ?
This is the typical way to do this:
for (int i = uids.Count - 1; i >= 0; i--)
Then, use uids[i] and maybe client.GetMessage(i), however I have no idea, what "client" is in your code
Arrays in C# (and all the other C-like languages) are zero-indexed, which means that the first item in the array is at position 0. Attempting to access an array index that is less than 0 or greater than or equal to the number of elements in the array will result in an error as you have seen.
The first form of your loop:
for (int i = uids.Count; i > 0; i--)
...produces a sequence of numbers (on your 7038-item array) from 7038 down to 1. Since 7038 is an invalid array index (1 past the end of the array) and the sequence doesn't include 0, the array access expressions in the loop all use i -1 to shift the entire sequence down by 1.
To properly reverse the for without changing any other code you need to produce a sequence from 1 up to 7038, like this:
for (int i = 1; i <= uids.Count; i++)
This is the direct opposite form of your original.
Personally I would prefer that the loop variable be the array index most of the time, and my first instinct when I see a > 0 condition in a for statement is that someone forgot to put the = in.
You could just reverse your array with Array.reverse() and then iterate over it using i++ as per your original approach
Oops I thought this was JavaScript question lol, o well the approach I said can conceptually be applied to any language, just need to find the array reverse for your language
If I understood correctly, originally i went from 0 to uids.Count - 1. If you can get back to that situation, then your formula for nProgress should be
int nProgress = (i + 1) * 100 / uids.Count;

parallel bidirectional selection sort

I wrote code to implement a bidirectional selection sort in parallel. I used c#, and the the parallel.invoke function. 2 loops were invoked in parallel, one to find the minimum, and one to find the max. Yet, it doesn't sort. I was wondering is the problem because this type of sort can't handle being done in parallel, since each loop relies on data existing in the other loop?...or is there simply something wrong with my code?
Parallel.Invoke(
() =>
{
for (int i=0; i < array.Length / 2; i++)
{
int m;
int min = i;
for (m = i + 1; m < array.Length - 1; m++)
if (array[m] < array[min])
min = m;
//swap
int temp = array[min];
array[min] = array[m];
array[m] = temp;
}
},
() =>
{
for (int m = 0; m < array.Length / 2; m++)
{
int length = array.Length - 1;
int max = length - m;
int k;
for (k = length--; k > 0; k--)
if (array[k] > array[max])
max = k;
//swap
int temp = array[max];
array[max] = array[k];
array[k] = temp;
}
});
I think it's easier if you search the minimum and maximum within the same loop in 1 thread: (java-code, but I assume you'll understand the principle)
int minimum, maximum;
int k = size();
for(int i = 0; i < size(); ++i)
{
--k;
minimum = i;
maximum = k;
if(k - i <= 0)
break;
for(int j = i; j <= k; ++j)
{
if(greaterThan(minimum, j))
minimum = j;
if(lessThan(maximum, j))
maximum = j;
}
if(minimum != i)
{
swap(minimum, i);
if(maximum == i)
maximum = minimum;
}
if(maximum != k)
swap(maximum, k);
}
The problem with your code is this:
Say this is the array:
[5, 4, 3, 2, 1]
Iteration 0: The first thread will find the smallest element to put on index 0
The first thread finds the minimum element at index 4
Iteration 0: The second thread will find the largest element to put on index 4
The second thread finds the maximum element at index 0
You will already see that this will not end well, as both threads will perform a swap between index 0 and 4 resulting in the same situation as it is now.
Another problem is if your first thread is looping from m -> array.length - 1. If at the same time thread 2 moves the minimum element (which it doesn't need, because it's searching the maximum) from index k to "max" via a swap. With index "max" being < "m". That means the first thread will never find the next minimum value because it was moved before its position.
EDIT: After consideration, I don't think it's possible to implement a straightforward parallel version of selection sort. The version I first recommended was indeed not going to work due to the algorithm finding the same minimum every time because it didn't change the input-array.
What is possible is to only perform selection sort with thread 1 on the first half of the array (and only allow it to find the minimum in that half) and the second half of the array is for the second thread. And then in the end you can merge both halfs with a mergesort-algorithm.
This way you can always use more than 2 threads; say "p" amount of threads for example. Each responsible for N/p part of the input array with "N" being the inputsize. And in the end you just merge every part with a mergesort-algorithm. I never implemented it myself, so I can't say if it would be efficient, but I assume there will be better algorithms to parallelize out there (like mergesort itself).
PS: About the code posted above. I assume everything seems rather straightforward except this part:
if(maximum == i)
maximum = minimum;
That's to deal with a situation like this:
. . . i . . . k
[1, 4, 3, 1, 5]
so with i = 1 and k = 3 (the indices).
The algorithm will find:
maximum = index 1
minimum = index 3
After swapping the minimum value with the one on index i, the situation changes like this:
. . . i . . . k
[1, 1, 3, 4, 5]
Meaning the maximum value (integer 4) actually moved from index "i" to index "minimum". If we would perform a swap(maximum, k), it would have a bad result. That's why we need to update the index of the maximum element if it was positioned at index i.

How to make this function process in constant time?

I need to find the n-th term of this infinite series: 1,2,2,3,3,3,4,4,4,4...
Can you give me a constant time function for this task?
int i = 1;
while(true)
{
if(i = n)
//do things and exit the loop
i++;
}
I think this isn`t going to be a constant time function...
Edit
After reading more comments, it appears I misunderstood the question.
If you want to find the item at nth position an array in constant time, then the answer is trivial: x[n], because array access is constant time. However, if for some reason you were using some container where access time is not constant (e.g. linked list), or did not want to look up value in the array, you'd have to use the arithmetic series formulas to find the answer.
Arithmetic series tells us that the position n of the ith unique item would be
n = i * (i - 1) / 2
So we just need to solve for i. Using quadratic formula, and discarding the nonsensical negative option, we get:
i = Math.Floor( (1 + Math.Sqrt(1 + 8 * n)) / 2)
Original Response
I'm assuming you're looking for the position of the nth unique term, because otherwise the problem is trivial.
Sounds like the first occurrence of the nth unique term should follow arithmetic series. I.e. the position of nth unique term would be:
n * (n - 1) / 2
Given my understanding of the problem, this is more of a math problem than a programming one.
If the problem is:
Given an infinite series that consists of 1 copy of 1, 2 copies of 2, 3 copies of 3... n copies of n, what is the kth value in this series?
Now the first clue when approaching this problem is that there are 1 + 2 + 3... + n values before the first occurance of n + 1. Specifically there are (sum of the first n numbers) values before n+1, or (n)(n-1)/2.
Now set (n)(n-1)/2 = k. Multiply out and rationalize to n^2 - n - 2k = 0. Solve using quadratic equation, you get n = (1 + sqrt(1+8k))/2. The floor of this gives you how many full copies of n there are before, and happily, given zero based indexing, the floor gives you the value at the kth point in the array.
That means your final answer in c# is
return (int) Math.Floor((1 + Math.Sqrt(1 + 8 * k)) / 2);
Given non zero based indexing,
return (int) Math.Floor((1 + Math.Sqrt(-7 + 8 * k)) / 2);
public static long Foo(long index)
{
if (index < 0)
{
throw new IndexOutOfRangeException();
}
long nowNum = 0;
long nowIndex = 0;
do
{
nowIndex += nowNum;
nowNum++;
} while (nowIndex < index);
return nowNum;
}

Categories