How to fix minimax algorithm - c++

Required to write a minimax algorithm that returns a value from a array of random numbers, the length of which is 2 ^ depth(the algorithm works on a binary tree).
my code:
int minimax(int* scores, unsigned int left, unsigned int right, int depth, bool search_max_score, bool& move)
{
if (search_max_score)
{
if (depth == 1)
{
int result = std::max(scores[left], scores[right]);
move = (result == scores[right]);
return result;
}
int left_value = minimax(scores, left, right / 2, depth - 1, false, move);
int right_value = minimax(scores, right / 2 + 1, right, depth - 1, false, move);
int result = std::max(left_value, right_value);
move = (result == right_value);
return result;
}
else
{
if (depth == 1)
{
int result = std::min(scores[left], scores[right]);
move = (result == scores[right]);
return result;
}
int left_value = minimax(scores, left, right / 2, depth - 1, true, move);
int right_value = minimax(scores, right / 2 + 1, right, depth - 1, true, move);
int result = std::min(left_value, right_value);
move = (result == right_value);
return result;
}
}
//score_num - array length
//search_max_score - which element to search for (false - minimum, true - maximum)
bool move;
int result = minimax(scores, 0, score_num - 1, depth, search_max_score, move);
std::cout << "result: " << result << '\n';
std::cout << "move: " << move;
But sometimes the program outputs the wrong value:
random values:
___/___ __\____
_/_ _\_ _/_ _\_
/ \ / \ / \ / \
-1 3 -5 1 -8 6 4 -7
result: 1
move: 0
move is the direction of the subsequent action of the AI. 0 - left, 1 - right

You have at least 2 bugs:
Inside if (search_max_score) block you call minmax with false as the 5th argument, which is equivalent to making the search for max element becoming a search for min element, and then max again, etc.
If you have an interval [left, right] and you want to halve it, the midpoint is NOT right/2 (unless left == 0), but rather (left + right)/2 or left + (right-left + 1)/2. You need to work on the exact form of this formula that will fit your needs, taking into account the integer rounding when dividing an odd integer by 2. Or you can calculate the offset from depth, as the interval length will always be a power of two.
The third point is not a bug, but an error it is: please use a debugger.

Related

My segment tree update function doesn't work properly

The problem:
In this task, you need to write a regular segment tree for the sum.
Input The first line contains two integers n and m (1≤n,m≤100000), the
size of the array and the number of operations. The next line contains
n numbers a_i, the initial state of the array (0≤a_i≤10^9). The following
lines contain the description of the operations. The description of
each operation is as follows:
1 i v: set the element with index i to v (0≤i<n, 0≤v≤10^9).
2 l r:
calculate the sum of elements with indices from l to r−1 (0≤l<r≤n).
Output
For each operation of the second type print the corresponding
sum.
I'm trying to implement segment tree and all my functions works properly except for the update function:
void update(int i, int delta, int v = 0, int tl = 0, int tr = n - 1)
{
if (tl == i && tr == i)
t[v] += delta;
else if (tl <= i && i <= tr)
{
t[v] += delta;
int m = (tl + tr) / 2;
int left = 2 * v + 1;
int right = left + 1;
update(i, delta, left, tl, m);
update(i, delta, right, m + 1, tr);
}
}
I got WA on segment tree problem, meanwhile with this update function I got accepted:
void update(int i, int new_value, int v = 0, int tl = 0, int tr = n - 1)
{
if (tl == i && tr == i)
t[v] = new_value;
else if (tl <= i && i <= tr)
{
int m = (tl + tr) / 2;
int left = 2 * v + 1;
int right = left + 1;
update(i, new_value, left, tl, m);
update(i, new_value, right, m + 1, tr);
t[v] = t[left] + t[right];
}
}
I really don't understand why my first version is not working. I thought maybe I had some kind of overflowing problem and decided to change everything to long longs, but it didn't help, so the problem in the algorithm of updating itself. But it seems ok to me. For every segment that includes i I need to add sum of this segment to some delta (it can be negative, if for example I had number 5 and decided to change it to 3, then delta will be -2). So what's the problem? I really don't see it :(
There are 2 problems with your first solution:
The question expects you to do a point update. The condition (tl == i && tr == i) checks if you are the leaf node of the tree.
At leaf node, you have to actually replace the value instead of adding something into it, which you did for the second solution.
Secondly, you can only update the non-leaf nodes after all its child nodes are updated. Updating t[v] before making recursive call will anyways result into wrong answer.

I have a variable and an matrix and how to move the elements right?

I have a matrix which is 3*3 for example, and I have a variable = 10.
This variable represents the first element of the new array. I need to store the last element as well in a new variable.
I need to move the matrix left to right, right to left, up to down, and down to up, by shifting the elements and getting the last element.
For example the default matrix:
[[0,1,2]
[3,4,5]
[6,7,8]]
Shifting the the first row with variable=5
[[5,0,1]
[3,4,5]
[6,7,8]]
and then I get back 2 the second result.
Another example shift from up to down the last column with variable=6:
[[5,0,6]
[3,4,2]
[6,7,5]]
and then I get back 8.
Here is a snippet of my c++ code, but I can accept every language.
#include <iostream>
using namespace std;
int main()
{
int ar[3][3] = {
{0, 1, 2} ,
{3, 4, 5} ,
{6, 7, 8}
};
int x=0;
for (int i = 0; i < 2; i++) {
int temp = x[i];
x[i]=x[i+1];
x[i]=tmp;
}
return 0;
}
We can generalize the directions in such a manner that the same code would handle all of the cases. The example below is a proof-of-concept, yet, it was not actually tested, because I lack a C++ env at the moment. But, if it turns out to be some problem with it, then it should be fairly easy to fix it, so if it does not work yet, then please provide example inputs and outputs.
int index = 0; //It can be something between 0 and 2
int isRow = 1; //It can be 1 if it's a row to be shifted and 0 if it's a column to be shifted
int direction = 1; //It can be -1 if it's to the left/up (depending on the value of isRow) and 1 if it's right/down
int output; //The element we need to store at the end
int input = 10; // The element we need to append
int i;
for (i = 0; i <= 2; i++) {
if (i == 0) output = ar[isRow ? index : (2 - (direction + 1) + direction * i)][isRow ? (2 - (direction + 1) + (direction * i)) : index];
else ar[isRow ? index : (2 - (direction + 1) + direction * i)][isRow ? (2 - (direction + 1) + (direction * (i - 1))) = ar[isRow ? index : (2 - (direction + 1) + direction * i)][isRow ? (2 - (direction + 1) + (direction * (i - 1)));
}

Maximum difference between sum of even and odd position elements: How to memoize the brute-force approach?

I have the following code for a problem.
The problem is: Maximize the absolute difference between the sum of elements at the even and odd positions of an array. To do so, you may delete as many elements you want.
I did it by brute-force by using backtracking. My logic is that, for each index I have 2 options:
a) either delete it (in this case, I put it in a set)
b) don't delete it (in this case, I removed the index from the set and backtracked).
I took the local maximum of two cases and updated the global maximum value appropriately.
void maxAns(vector<int> &arr, int index, set<int> &removed, int &res)
{
if (index<0)
return;
int k=0;
int s3=0,s4=0;
for (int i=0;i<arr.size();i++)
{
if (i!=index)
{
set<int>::iterator it=removed.find(i);
if (it==removed.end())
{
if( k%2==0)
s3+=arr[i];
else
s4+=arr[i];
k++;
}
}
else //don't delete the element
{
if (k%2==0)
s3+=arr[i];
else
s4+=arr[i];
k++;
}
}
k=0;
int s1=0, s2=0;
for (int i=0;i<arr.size();i++)
{
if (i!=index)
{
set<int>::iterator it=removed.find(i);
if (it==removed.end())
{
if (k%2==0)
s1+=arr[i];
else
s2+=arr[i];
k++;
}
}
else //delete the element
{
//add index into the removed set
removed.insert(index);
}
}
//delete the index element
int t1=abs(s1-s2);
maxAns(arr,index-1,removed,res);
//don't delete the index element, and then backtrack
set<int>::iterator itr=removed.find(index);
removed.erase(itr);
int t2=abs(s3-s4);
maxAns(arr,index-1,removed,res);
//choose the max value
res=max(res,max(t1,t2));
}
Please suggest how to memoize this solution as I think it's quite inefficient. Feel free to share any interesting approach.
Hint: divide and conquer. Consider that a fixed length list as a left part of a larger list, maximised (or minimised) for the actual, rather than abdolute difference and depending on the parity of its length, would pair better with a right part that does not depend on the parity of its length.
[0,3] ++ [0,3] -> diff -3 -3 = -6
[0,3] ++ [9,13,1] -> diff -3 -3 = -6
We can also easily create base cases for max_actual_diff and min_actual_diff of lists with lengths 1 and 2. Note that the best choice for those might include ommiting one or more of those few elements.
JavaScript code:
function max_diff(A, el, er, memo){
if (memo[['mx', el, er]])
return memo[['mx', el, er]]
if (er == el)
return memo[['mx', el, er]] = [A[el], 1, 0, 0]
var best = [A[el], 1, 0, 0]
if (er == el + 1){
if (A[el] - A[er] > best[2]){
best[2] = A[el] - A[er]
best[3] = 2
}
if (A[er] > best[0]){
best[0] = A[er]
best[1] = 1
}
return memo[['mx', el, er]] = best
}
const mid = el + ((er - el) >> 1)
const left = max_diff(A, el, mid, memo)
const right_min = min_diff(A, mid + 1, er, memo)
const right_max = max_diff(A, mid + 1, er, memo)
// Best odd = odd + even
if (left[0] - right_min[2] > best[0]){
best[0] = left[0] - right_min[2]
best[1] = left[1] + right_min[3]
}
// Best odd = even + odd
if (left[2] + right_max[0] > best[0]){
best[0] = left[2] + right_max[0]
best[1] = left[3] + right_max[1]
}
// Best even = odd + odd
if (left[0] - right_min[0] > best[2]){
best[2] = left[0] - right_min[0]
best[3] = left[1] + right_min[1]
}
// Best even = even + even
if (left[2] + right_max[2] > best[2]){
best[2] = left[2] + right_max[2]
best[3] = left[3] + right_max[3]
}
return memo[['mx', el, er]] = best
}
function min_diff(A, el, er, memo){
if (memo[['mn', el, er]])
return memo[['mn', el, er]]
if (er == el)
return memo[['mn', el, er]] = [A[el], 1, 0, 0]
var best = [A[el], 1, 0, 0]
if (er == el + 1){
if (A[el] - A[er] < best[2]){
best[2] = A[el] - A[er]
best[3] = 2
}
if (A[er] < best[0]){
best[0] = A[er]
best[1] = 1
}
return memo[['mn', el, er]] = best
}
const mid = el + ((er - el) >> 1)
const left = min_diff(A, el, mid, memo)
const right_min = min_diff(A, mid + 1, er, memo)
const right_max = max_diff(A, mid + 1, er, memo)
// Best odd = odd + even
if (left[0] - right_max[2] < best[0]){
best[0] = left[0] - right_max[2]
best[1] = left[1] + right_max[3]
}
// Best odd = even + odd
if (left[2] + right_min[0] < best[0]){
best[0] = left[2] + right_min[0]
best[1] = left[3] + right_min[1]
}
// Best even = odd + odd
if (left[0] - right_max[0] < best[2]){
best[2] = left[0] - right_max[0]
best[3] = left[1] + right_max[1]
}
// Best even = even + even
if (left[2] + right_min[2] < best[2]){
best[2] = left[2] + right_min[2]
best[3] = left[3] + right_min[3]
}
return memo[['mn', el, er]] = best
}
var memo = {}
var A = [1, 2, 3, 4, 5]
console.log(`A: ${ JSON.stringify(A) }`)
console.log(
JSON.stringify(max_diff(A, 0, A.length-1, memo)) + ' // [odd max, len, even max, len]')
console.log(
JSON.stringify(min_diff(A, 0, A.length-1, memo)) + ' // [odd min, len, even min, len]')
console.log('\nmemo:\n' + JSON.stringify(memo))
Maximize the absolute difference between the sum of elements at the odd and even positions of an array. To do so, you may delete as many elements as you want.
Example
A = [9, 5, 2, 9, 4]
Ans = 16 => [9, 2, 9] = 9-2+9
A = [8, 6, 2, 7, 7, 2, 7]
Ans = 18 => [8, 2, 7, 2, 7] = 8-2+7-2+7
Hint:
At the position "i+1", Let the maximum and minimum possible difference for all the subsequences of subarray A[i+1,n] be Max, Min respectively
Hence at position "i", the maximum and minimum possible difference for all the subsequences of subarray A[i, n] can be calculated as
Include the current element arr[i]
Don't Include the current element arr[I]
Max = MAX(Max, arr[i] - Min)
Min = MIN(Min, arr[i] - Max)
Explanation:
A = 9, 5, 2, 9, 4
Max = 16, 12, 9, 9, 4
Min = -7, -7, -7, 0, 0
Final Answer: Max(Max[0], Min[0]) = Max(16, -7) = 16
Time Complexity: O(n)
Space Complexity: O(1) * As Just 2 variables Max, Min were used*
Let's say we always add the values at even positions and we always rest the values at odd positions. Now, we will iterate from 1 to 𝑛n and make choices: keep the element or delete it; the thing is that when we keep an element, we need to know if it is at an even position or an odd position, so we will do Dynamic Programming:
𝑑𝑝[𝑖][0]dp[i][0]: max possible sum using the elements in 𝑎1,𝑎2,…,𝑎𝑖a1,a2,…,ai and the resulting array is of even length.
𝑑𝑝[𝑖][1]dp[i][1]: same as above, but now the resulting array is of odd length.
Transitions are: keep it or delete it.
𝑑𝑝[𝑖][𝑟]=max(𝑑𝑝[𝑖−1][𝑟],𝑑𝑝[𝑖−1][!𝑟]+𝑎[𝑖]∗((𝑟==0)?1:−1)dp[i][r]=max(dp[i−1][r],dp[i−1][!r]+a[i]∗((r==0)?1:−1);
Now it's when someone says: Wait minute, you are always adding at even positions and resting at odd positions, what if it's of the other way. Well, for this, perform again the DP but adding at odd positions and resting at even positions. You stay with the maximum of both solutions

Game of Life Neighbour Check (easier method possible?)

I am trying to make the game of life in c++ at the moment, this is my first C++ exercise ever. I have one question, we need to make some game modes like one is called "torus" where cells that leave the board should re-enter it on the opposite side.
Now, i am checking the neighbours right now. But i am hardcoding it with hell a lot of if clauses, because i tried some for-loops but it did not work.
But is this really the only option? To hardcode every possibility (cells on the left side, on the right side, upper side, lower side etc?
This is a fragment of the code i have for that:
int countNeighboursTorus(int a, int b) {
int living = 0;
// when the starting cell is the one on the upper left (start of the board)
if (a == 0 && b == 0) {
// cell below
if (board[a - 1][b] != DEAD) {
living++;
}
// cell right below
if (board[a + 1][b + 1] != DEAD) {
living++;
}
// cell right
if (board[a][b + 1] != DEAD) {
living++;
}
// cell above (other side of the board)
if (board[HEIGHT - 1][b] != DEAD) {
living++;
}
// cell above right (other side of the board)
if (board[HEIGHT - 1][b + 1] != DEAD) {
living++;
}
}
// first edge case (height = 0, width != 0):
else if (a == 0 && b != 0) {
// cell below
if (board[a - 1][b] != DEAD) {
living++;
}
// cell right below
if (board[a + 1][b + 1] != DEAD) {
living++;
}
// cell right
if (board[a][b + 1] != DEAD) {
living++;
}
// cell left below
if (board[a + 1][b - 1] != DEAD) {
living++;
}
// cell left
if (board[a][b - 1] != DEAD) {
living++;
}
// cell left above (other side of the board)
if (board[HEIGHT - 1][b - 1] != DEAD) {
living++;
}
// cell above (other side of the board)
if (board[HEIGHT - 1][b] != DEAD) {
living++;
}
// cell above right (other side of the board)
if (board[HEIGHT - 1][b + 1] != DEAD) {
living++;
}
}
return living;
}
One of the for loops i wrote, but did not really work, was the following - the loop counted too many cells all the time. After the loop, all the cells ALWAYS had the dead status because the program always counted more than 3 living cells, even if only 2 cells were living from the start. I hope this explanation is helpful, it is a little bit hard to explain. I made an outprint - "+" - and it usually showed about 5/6 plusses, even if it should only show it twice (two living cells).
// for any other "normal" cases inside of the board:
else if (a != 0 && b != 0 && a < HEIGHT - 1 && b < WIDTH - 1) {
for (int c = -1; c < 2; c++) {
for (int d = -1; d < 2; d++) {
if (!(c == 0 && d == 0)) {
if (board[a + c][b + d] != DEAD) {
living++;
}
}
}
}
}
Is there ANY option to simplify that? For instance with loops, like i tried? Or is that the way it should be done? I am really not seeing the light on the end of the tunnel right now. Just so that i know if i am doing this for nothing. I am really having some problems with the C++ syntax because i only did Java for about a year until now, so i am a beginner when it comes to C++. I am grateful for any tips!
Yes. Use the modulus operator:
Instead of
if (board[a + 1][b + 1] != DEAD) {
use:
if (board[(a + 1) % HEIGHT][(b + 1) % WIDTH] != DEAD) {
There is a slight complexity when you doing subtraction (% isn't actually the modulus operation, it's the remainder operation). You don't want to use it on -1 (it will just return -1), so add an additional HEIGHT/WIDTH:
if (board[(a - 1 + HEIGHT) % HEIGHT][(b - 1 + WIDTH) % WIDTH] != DEAD) {
You can then use the same code for all the cells of the board.
This line tries to access elements of the matrix that are not in matrix range:
if (board[a + c][b + d] != DEAD) {
Before executing this line you have to check if a + c and b + d are in matrix range, and if they are not what should be done instead. For "torus" requirement I guess "left" and "right" out of range should be replaced with wrapped values, and "top" and "bottom" out of range should be just skipped.
In addition to Martin Bonner's answer, prepare the table of offsets to eight neighbors:
static const int NoOfNeighbors = 8;
int dVertNeigh [NoOfNeighbors] = {
HEIGHT-1, HEIGHT-1, HEIGHT-1,
0, 0,
1, 1, 1};
int dHorizNeigh [NoOfNeighbors] = {
WIDTH-1, 0, 1,
WIDTH-1, 1,
WIDTH-1, 0, 1};
then you can count neighbor cells with a simple loop:
for (int ngh = 0; ngh < NoOfNeighbors; ngh++) {
int neighborV = (a + dVertNeigh[ngh]) % HEIGHT;
int neighborH = (b + dHorizNeigh[ngh]) % WIDTH;
if (board[neighborV][neighborH] != DEAD) {
living++;
}
}

Find all peaks for Mat() in OpenCV C++

I want to find all maximums (numbers of non-zero pixels) for my image. I need it to divide my picture such way:
So, i already asked question, how to project all image to one of the axis, and now i need to find all maximums on this one-row image.
Here's my part of the code:
void segment_plate (Mat input_image) {
double minVal;
double maxVal;
Point minLoc;
Point maxLoc;
Mat work_image = input_image;
Mat output;
//binarize image
adaptiveThreshold(work_image,work_image, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 15, 10);
//project it to one axis
reduce(work_image,output,0,CV_REDUCE_SUM,CV_32S);
//find minimum and maximum falue for ALL image
minMaxLoc(output, &minVal,&maxVal,&minLoc,&maxLoc);
cout << "min val : " << minVal << endl;
cout << "max val: " << maxVal << endl;
As you can see, i could find one maximum and one minimum for all picture, but i need to find local maximums. Thanks for any help!
EDIT
Ok, so i made a mistake, i need to find peaks for this vector. I've used this code to find first peak:
int findPeakUtil(Mat arr, int low, int high, int n) {
// Find index of middle element
int mid = low + (high - low)/2; /* (low + high)/2 */
// Compare middle element with its neighbours (if neighbours exist)
if ((mid == 0 || arr.at<int>(0,mid-1) <= arr.at<int>(0,mid)) &&
(mid == n-1 || arr.at<int>(0,mid+1) <= arr.at<int>(0,mid)))
return mid;
// If middle element is not peak and its left neighbor is greater than it
// then left half must have a peak element
else if (mid > 0 && arr.at<int>(0,mid-1) > arr.at<int>(0,mid))
return findPeakUtil(arr, low, (mid - 1), n);
// If middle element is not peak and its right neighbor is greater than it
// then right half must have a peak element
else return findPeakUtil(arr, (mid + 1), high, n);
}
// A wrapper over recursive function findPeakUtil()
int findPeak(Mat arr, int n) {
return findPeakUtil(arr, 0, n-1, n);
}
So now my code looks like:
void segment_plate (Mat input_image) {
Mat work_image = input_image;
Mat output;
//binarize image
adaptiveThreshold(work_image,work_image, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 15, 10);
//project it to one axis
reduce(work_image,output,0,CV_REDUCE_SUM,CV_32S);
int n = output.cols;
printf("Index of a peak point is %d", findPeak(output, n));
But how can i find another peaks? The algorithm of peak finding i took from here.
One way I can think about to find peaks is to find the first derivative and then find the negative numbers of it.
for example,
a = [ 1, 2, 3, 4, 4, 5, 6, 3, 4]
in this example the peak is 6 in the position 6 and 4 in the las position.
so, if you extend the vector (0 at the end) and apply the first derivative (a[i] - a[i-1]) you'll get
a_deriv = [1,1,1,0,1,1,-3,1,-4]
where the negative numbers are in the position of the peaks. In this case, -3 is in position 6 and -4 in position 8, that is where the peaks are located.
This is a way to do it.... but is not the only one.
Note that this method will count only the last number in a plateau as the peak ( you can find a plateau when two numbers share the peak because they have the same value and are consecutive)
Hope this helps you