Related
I posted a similar question to this one a few weeks ago where I had trouble finding the data race in my N-queens program using pthreads in C. Why is my multithreaded C program not working on macOS, but completely fine on Linux?
I got a few suggestions in the comments sections of the post and I really tried my best to make corrections based on them. I sat with the suggestions a few days, changed some parts but the data race persisted and I just cannot understand why. There are counters inside critical sections for the number of productions and consumptions. I feel completely blind when looking through the code and analyzing it, I'm aware that consumptions are too many but the synchronization around that code fragment should with my knowledge be correct, but obviously something's not right. External input would be greatly appreciated.
This is the code I'm using and I'm not sure how to reduce its size to still reproduce the issue. I compile it with gcc (clang-1205.0.22.11) on macOS Monterey (12.1) using a MacBook Pro 2020 x86_64 architecture.
compile: gcc -o 8q 8q.c*
run: ./8q <consumers> <N>, NxN chess board, N queens to place
parameters: ./8q 2 4 Enough to highlight the problem (should yield 2 solutions, but every other run yields 3+ solutions, i.e duplicate solutions exist
note: running the program with ./8q 2 4 should give 2 solutions, 1820 productions and 1820 consumptions.
#ifndef _REENTRANT
#define _REENTRANT
#endif
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
typedef struct stack_buf {
int positions[8];
int top;
} stack_buf;
typedef struct global_buf {
int positions[8];
int buf_empty;
long prod_done;
int last_done;
} global_buf;
typedef struct print_buf {
int qpositions[100][8];
int top;
} print_buf;
stack_buf queen_comb = { {0}, 0 };
print_buf printouts = { {{0}}, 0 };
global_buf global = { {0}, 1, 0, 0 };
int N; //NxN board and N queens to place
long productions = 0;
long consumptions = 0;
pthread_mutex_t buffer_mutex, print_mutex;
pthread_cond_t empty, filled;
/* ##########################################################################################
################################## VALIDATION FUNCTIONS ##################################
########################################################################################## */
/* Validate that no queens are placed on the same row */
int valid_rows(int qpositions[]) {
int rows[N];
memset(rows, 0, N*sizeof(int));
int row;
for (int i = 0; i < N; i++) {
row = qpositions[i] / N;
if (rows[row] == 0) rows[row] = 1;
else return 0;
}
return 1;
}
/* Validate that no queens are placed in the same column */
int valid_columns(int qpositions[]) {
int columns[N];
memset(columns, 0, N*sizeof(int));
int column;
for (int i = 0; i < N; i++) {
column = qpositions[i] % N;
if (columns[column] == 0) columns[column] = 1;
else return 0;
}
return 1;
}
/* Validate that left and right diagonals aren't used by another queen */
int valid_diagonals(int qpositions[]) {
int left_bottom_diagonals[N];
int right_bottom_diagonals[N];
int row, col, temp_col, temp_row, fill_value, index;
for (int queen = 0; queen < N; queen++) {
row = qpositions[queen] / N;
col = qpositions[queen] % N;
/* position --> left down diagonal endpoint (index) */
fill_value = col < row ? col : row; // closest to bottom or left wall
temp_row = row - fill_value;
temp_col = col - fill_value;
index = temp_row * N + temp_col; // board position
for (int i = 0; i < queen; i++) { // check if interference occurs
if (left_bottom_diagonals[i] == index) return 0;
}
left_bottom_diagonals[queen] = index; // no interference
/* position --> right down diagonal endpoint (index) */
fill_value = (N-1) - col < row ? N - col - 1 : row; // closest to bottom or right wall
temp_row = row - fill_value;
temp_col = col + fill_value;
index = temp_row * N + temp_col; // board position
for (int i = 0; i < queen; i++) { // check if interference occurs
if (right_bottom_diagonals[i] == index) return 0;
}
right_bottom_diagonals[queen] = index; // no interference
}
return 1;
}
/* ##########################################################################################
#################################### HELPER FUNCTION(S) ####################################
########################################################################################## */
/* print the collected solutions */
void print(print_buf printouts) {
static int solution_number = 1;
int placement;
pthread_mutex_lock(&print_mutex);
for (int sol = 0; sol < printouts.top; sol++) { // all solutions
printf("Solution %d: [ ", solution_number++);
for (int pos = 0; pos < N; pos++) {
printf("%d ", printouts.qpositions[sol][pos]+1);
}
printf("]\n");
printf("Placement:\n");
for (int i = 1; i <= N; i++) { // rows
printf("[ ");
placement = printouts.qpositions[sol][N-i];
for (int j = (N-i)*N; j < (N-i)*N+N; j++) { // physical position
if (j == placement) {
printf(" Q ");
} else printf("%2d ", j+1);
}
printf("]\n");
}
printf("\n");
}
pthread_mutex_unlock(&print_mutex);
}
/* ##########################################################################################
#################################### THREAD FUNCTIONS ####################################
########################################################################################## */
/* entry point for each worker (consumer) workers will
check each queen's row, column and diagonal to evaluate
satisfactory placements */
void *eval_positioning(void *id) {
long thr_id = (long)id;
int qpositions[N]; // on stack (thread-private)
while (1) {
pthread_mutex_lock(&buffer_mutex);
while (global.buf_empty == 1) { // no element
if (global.last_done) { // last done, no combinations left
pthread_mutex_unlock(&buffer_mutex);
pthread_cond_signal(&filled);
return NULL;
}
if (global.prod_done) {
global.last_done = 1;
break;
}
pthread_cond_wait(&filled, &buffer_mutex);
}
memcpy(qpositions, global.positions, N*sizeof(int)); // copy to local scope
global.buf_empty = 1;
consumptions++;
pthread_mutex_unlock(&buffer_mutex);
pthread_cond_signal(&empty);
if (valid_rows(qpositions) && valid_columns(qpositions) && valid_diagonals(qpositions)) {
pthread_mutex_lock(&print_mutex);
memcpy(printouts.qpositions[printouts.top], qpositions, N*sizeof(int)); /* save for printing later */
printouts.top++;
pthread_mutex_unlock(&print_mutex);
}
}
return NULL;
}
/* recursively generate all possible queen_combs */
void rec_positions(int pos, int queens) {
if (queens == 0) { // base case
pthread_mutex_lock(&buffer_mutex);
while (global.buf_empty == 0) { // while production hasn't been consumed
pthread_cond_wait(&empty, &buffer_mutex);
}
memcpy(global.positions, queen_comb.positions, N*sizeof(int));
productions++;
global.buf_empty = 0;
pthread_mutex_unlock(&buffer_mutex);
pthread_cond_signal(&filled);
return;
}
for (int i = pos; i <= N*N - queens; i++) {
queen_comb.positions[queen_comb.top++] = i;
rec_positions(i+1, queens-1);
queen_comb.top--;
}
}
/* binomial coefficient | without order, without replacement
8 queens on 8x8 board: 4'426'165'368 queen combinations */
void *generate_positions(void *arg) {
rec_positions(0, N);
pthread_mutex_lock(&buffer_mutex);
global.prod_done = 1;
pthread_mutex_unlock(&buffer_mutex);
pthread_cond_broadcast(&filled); //wake all to
return NULL;
}
/* ##########################################################################################
########################################## MAIN ##########################################
########################################################################################## */
/* main procedure of the program */
int main(int argc, char *argv[]) {
if (argc < 3) {
printf("usage: ./8q <workers> <board width/height>\n");
exit(1);
}
int workers = atoi(argv[1]);
N = atoi(argv[2]);
if (N < 2 || N > 8) {
printf("Wrong input! 2 <= N <= 8\n");
return 0;
}
struct timeval start, stop;
double elapsed;
pthread_t consumers[workers];
pthread_t producer;
printf("\n");
gettimeofday(&start, NULL);
pthread_create(&producer, NULL, generate_positions, NULL);
for (long i = 0; i < workers; i++) {
pthread_create(&consumers[i], NULL, eval_positioning, (void*)i+1);
}
pthread_join(producer, NULL);
for (int i = 0; i < workers; i++) {
pthread_join(consumers[i], NULL);
char id[2];
sprintf(id, "%d", i+1);
write(1, id, strlen(id));
write(1, " done\n\n", 6);
}
gettimeofday(&stop, NULL);
elapsed = stop.tv_sec - start.tv_sec;
elapsed += (stop.tv_usec - start.tv_usec) / (double)1000000;
/* go through all valid solutions and print */
print(printouts);
printf("board: %dx%d, workers: %d (+1), exec time: %fs, solutions: %d\n", N, N, workers, elapsed, printouts.top);
printf("productions: %ld\nconsumptions: %ld\n", productions, consumptions);
return 0;
}
You're not initializing your mutexes and condition variables. The result is UB when used in pthread APIs. Two ways to do this, the simplest is just use the proper initializer:
pthread_mutex_t buffer_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t print_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t empty = PTHREAD_COND_INITIALIZER;
pthread_cond_t filled = PTHREAD_COND_INITIALIZER;
Unrelated, but worth mentioning, the last_done ideology is not necessary. This can be done with just the buf_empty and prod_done states. Specifically:
void *eval_positioning(void *tid)
{
int qpositions[N]; // on stack (thread-private)
while (1)
{
pthread_mutex_lock(&buffer_mutex);
// while still producing *and* the buffer is empty
while (!global.prod_done && global.buf_empty)
pthread_cond_wait(&filled, &buffer_mutex);
// if both are true, we're done. nothing to process, and
// there never will be (e.g. prod_done)
if (global.prod_done && global.buf_empty)
{
// signal anyone else waiting on that mutex+cvar
pthread_cond_signal(&filled);
break;
}
// if we have a buffer to process (even if prod_done is true)
else if (!global.buf_empty)
{
// make local copy of buffer
memcpy(qpositions, global.positions, sizeof qpositions);
++consumptions;
// mark global buffer as ready-to-receive
global.buf_empty = 1;
pthread_cond_signal(&empty);
pthread_mutex_unlock(&buffer_mutex);
// if validated...
if (valid_rows(qpositions) && valid_columns(qpositions) && valid_diagonals(qpositions))
{
// record and bump the printout counter.
pthread_mutex_lock(&print_mutex);
int row = printouts.top++;
pthread_mutex_unlock(&print_mutex);
// this need not be protected by the mutex. we "own"
// this now, and can just blast away.
memcpy(printouts.qpositions[row], qpositions, sizeof qpositions);
}
}
else
{
pthread_mutex_unlock(&buffer_mutex);
}
}
// make sure we unlock this
pthread_mutex_unlock(&buffer_mutex);
return tid;
}
With proper initialization of the concurrency materials, and the above eval processor, this is the consistent output:
Output
1 done
2 done
Solution 1: [ 2 8 9 15 ]
Placement:
[ 13 14 Q 16 ]
[ Q 10 11 12 ]
[ 5 6 7 Q ]
[ 1 Q 3 4 ]
Solution 2: [ 3 5 12 14 ]
Placement:
[ 13 Q 15 16 ]
[ 9 10 11 Q ]
[ Q 6 7 8 ]
[ 1 2 Q 4 ]
board: 4x4, workers: 2 (+1), exec time: 0.013001s, solutions: 2
productions: 1820
consumptions: 1820
Apologies for the puny laptop performance numbers
I am given 2 arrays, Input and Output Array. The goal is to transform the input array to output array by performing shifting of 1 value in a given step to its adjacent element. Eg: Input array is [0,0,8,0,0] and Output array is [2,0,4,0,2]. Here 1st step would be [0,1,7,0,0] and 2nd step would be [0,1,6,1,0] and so on.
What can be the algorithm to do this efficiently? I was thinking of performing BFS but then we have to do BFS from each element and this can be exponential. Can anyone suggest solution for this problem?
I think you can do this simply by scanning in each direction tracking the cumulative value (in that direction) in the current array and the desired output array and pushing values along ahead of you as necessary:
scan from the left looking for first cell where
cumulative value > cumulative value in desired output
while that holds move 1 from that cell to the next cell to the right
scan from the right looking for first cell where
cumulative value > cumulative value in desired output
while that holds move 1 from that cell to the next cell to the left
For your example the steps would be:
FWD:
[0,0,8,0,0]
[0,0,7,1,0]
[0,0,6,2,0]
[0,0,6,1,1]
[0,0,6,0,2]
REV:
[0,1,5,0,2]
[0,2,4,0,2]
[1,1,4,0,2]
[2,0,4,0,2]
i think BFS could actually work.
notice that n*O(n+m) = O(n^2+nm) and therefore not exponential.
also you could use: Floyd-Warshall algorithm and Johnson’s algorithm, with a weight of 1 for a "flat" graph, or even connect the vertices in a new way by their actual distance and potentially save some iterations.
hope it helped :)
void transform(int[] in, int[] out, int size)
{
int[] state = in.clone();
report(state);
while (true)
{
int minPressure = 0;
int indexOfMinPressure = 0;
int maxPressure = 0;
int indexOfMaxPressure = 0;
int pressureSum = 0;
for (int index = 0; index < size - 1; ++index)
{
int lhsDiff = state[index] - out[index];
int rhsDiff = state[index + 1] - out[index + 1];
int pressure = lhsDiff - rhsDiff;
if (pressure < minPressure)
{
minPressure = pressure;
indexOfMinPressure = index;
}
if (pressure > maxPressure)
{
maxPressure = pressure;
indexOfMaxPressure = index;
}
pressureSum += pressure;
}
if (minPressure == 0 && maxPressure == 0)
{
break;
}
boolean shiftLeft;
if (Math.abs(minPressure) > Math.abs(maxPressure))
{
shiftLeft = true;
}
else if (Math.abs(minPressure) < Math.abs(maxPressure))
{
shiftLeft = false;
}
else
{
shiftLeft = (pressureSum < 0);
}
if (shiftLeft)
{
++state[indexOfMinPressure];
--state[indexOfMinPressure + 1];
}
else
{
--state[indexOfMaxPressure];
++state[indexOfMaxPressure + 1];
}
report(state);
}
}
A simple greedy algorithm will work and do the job in minimum number of steps. The function returns the total numbers of steps required for the task.
int shift(std::vector<int>& a,std::vector<int>& b){
int n = a.size();
int sum1=0,sum2=0;
for (int i = 0; i < n; ++i){
sum1+=a[i];
sum2+=b[i];
}
if (sum1!=sum2)
{
return -1;
}
int operations=0;
int j=0;
for (int i = 0; i < n;)
{
if (a[i]<b[i])
{
while(j<n and a[j]==0){
j++;
}
if(a[j]<b[i]-a[i]){
operations+=(j-i)*a[j];
a[i]+=a[j];
a[j]=0;
}else{
operations+=(j-i)*(b[i]-a[i]);
a[j]-=(b[i]-a[i]);
a[i]=b[i];
}
}else if (a[i]>b[i])
{
a[i+1]+=(a[i]-b[i]);
operations+=(a[i]-b[i]);
a[i]=b[i];
}else{
i++;
}
}
return operations;
}
Here -1 is a special value meaning that given array cannot be converted to desired one.
Time Complexity: O(n).
Prelude
I am writing a grid-based random-map generator.
Currently, I want to populate a 2D array with a variety of tiles.
Problem
In the parenthesis is a more concrete example.
Here is what you are given:
2D array and its dimensions. (i.e. 3x4 grid)
Integer Random(Range) (i.e. Range: 0-11, Output: integer from 0-11)
You do NOT have a function that randomly sorts an array, unless you implement it yourself.
Number of each type of tile (i.e. Desert: 2, Lake: 4, Forrest: 6)
How do I populate this array with the given tiles?
Example
3x4 map; 6 Forrest; 4 Lake; 2 Desert...
F F L
L D F
D F F
L F L
Attempt
I do have my own implementation, however its Big-O is... infinity, I think. :)
Of course, the chances that it will never finish are slim; however, this is part of a video game and I don't want to keep the player waiting.
Postscript
I don't really care what language that it is implemented in; pseudo-code will be satisfactory.
make sure the inputs are correct (e.g. total count of tiles equals
the count of slots in the grid)
put all give tiles into a queue Q, whose length is n(in your
example, n=12)
intialize a result array R[p], p is intialized as 0
get k=random(1->n), deque Q[k] into R[p], p++
repeat step 4 until p goes to n
Things can be much more easier if you use a language that has built-in sort functions:
verify input
put given tiles into an one demension array A[n]
sort A[n] randomly
Code in C#:
int m = 3;
int n = 4; //m*n grid
int forrests = 6;
int lakes = 4;
int deserts = 2;
if (m * n != forrests + lakes + deserts)
{
//invalid input!
}
char[] tiles = new char[m * n];
for (int i = 0; i < m * n; i++)
{
if (i < forrests)
{
tiles[i] = 'F';
}
else if (i < forrests + lakes)
{
tiles[i] = 'L';
}
else
{
tiles[i] = 'D';
}
}
//preparation completed, now tiles[] looks like
//F,F,F,F,F,F,L,L,L,L,D,D
char[] output = tiles.OrderBy(t => Guid.NewGuid()).ToArray();
//output is randomly sorted from tiles
//if you really need a two-demension array
char[][] map = new char[n][];
for (int i = 0; i < n; i++)
{
map[i] = output.Skip(m * i).Take(m).ToArray();
}
This could one of the way to do it.
#include<iostream>
#include <cstdlib>
#include <map>
using namespace std;
//Map which keeps the value for each key (2,4,6)
map<int,char> alphabet;
void initMap()
{
alphabet[2] = 'D';
alphabet[4] = 'L';
alphabet[6] = 'F';
}
int main()
{
char a[3][4];
// counter variables to keep track of d,f and l
int temp,d=0,f=0,l=0;
initMap();
for(int i=0;i<3;i++)
{
for(int j=0;j<4;j++)
{
//This determines if the generated random number is already entered in the grid. If no than breaks out. If yes than again a new random number is generated and process is iterated untill the new number is found to enter
while(1)
{
temp = rand()%4;
if(temp==0)
{
temp = 2;
}
else
{
temp = temp*2;
}
if(temp ==2 && d<2)
{
d++;
break;
}
else if(temp ==4 && l<4)
{
l++;
break;
}
else if(temp ==6 && f<6)
{
f++;
break;
}
else
{
continue;
}
}
//char value for the number temp is assigned from the alphabet map
a[i][j] = alphabet.at(temp);
cout<<a[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
output:
D F L D
L L L F
F F F F
You can map the alphabet according the number when entering the value or accessing the value from array.
Let's say I have an array with [2,4,6,7, 7, 4,4]
I want a program that can iterate through, and then print out something like this:
Value: Count:
2 1
4 3
6 1
7 2
I don't want it to print out ex 4 three times.
What I got so far:
for (int i = 0; i < numberOfInts; i++)
{
dub[i] = 0;
for (int y = 0; y < numberOfInts; y++)
{
if (enarray[i] == enarray[y])
{
dub[i]++;
}
}
}
So basically I check each element in the array against all the elements, and for every duplicate I add one to the index in the new array dub[].
So if I ran this code with the example array above, and then printed it out with I'd get something like this:
1,3,1,2,2,3,3. These are pretty confusing numbers, because I don't really know which numbers these belong to. Especially when I'll randomize the numbers in the array. And then I have to remove numbers so I only have one of each. Anyone got a better solution?
You can iterate through the array while checking for each element if it has been repeated in which case you increment it's count (the loop checks only values a head saving processing time). This let you accomplish what you needed without creating any extra buffer array or structure.
The bool 'bl' prevents repeated printing
int main() {
int arr[] = { 2, 4, 6, 7, 7, 4, 4 };
int size = (sizeof(arr) / sizeof(int));
printf("Value:\tCount\n");
for (int i = 0; i < size; i++) {
int count = 0, bl = 1; //or 'true' for print
//check elements ahead and increment count if repeated value is found
for (int j = i; j < size; j++) {
if (arr[i] == arr[j]) {
count++;
}
}
//check if it has been printed already
for (int j = i-1; j >= 0; j--) {
if (arr[i] == arr[j]) {
bl = 0; //print 'false'
}
}
if (bl) { printf("%d\t\t%d\n", arr[i], count); }
}
return 0;
}
Given the char array only contains '0' to '9', you may utilize a trivial lookup table like this:
#include <stdio.h>
typedef struct
{
char c;
int num;
} TSet;
TSet my_set[] =
{
{ '0', 0 },
{ '1', 0 },
{ '2', 0 },
{ '3', 0 },
{ '4', 0 },
{ '5', 0 },
{ '6', 0 },
{ '7', 0 },
{ '8', 0 },
{ '9', 0 },
};
int main()
{
char a[] = {'2','4','6','7','7', '4','4'};
int i;
for( i = 0; i < sizeof(a) / sizeof(char); i++ )
{
my_set[ a[i] - '0' ].num++;
}
printf( "%-10s%-10s\n", "Value:", "Count:" );
for( i = 0; i < sizeof(my_set) / sizeof(TSet); i++ )
{
if( my_set[i].num != 0 )
{
printf( "%-10c%-10d\n", my_set[i].c, my_set[i].num );
}
}
}
Output:
Value: Count:
2 1
4 3
6 1
7 2
I don't understand the complexity here. I think there are two approaches that are performant and easy to implement:
Counting Sort
requires int array of size of the biggest element in your array
overall complexity O(n + m) where m is the biggest element in your array
qsort and enumeration
qsort works in O(n * log(n)) and gives you a sorted array
once the array is sorted, you can simply iterate over it and count
overall complexity O(n*log(n))
sort the array, typically by using the qsort() function
iterate over all elements counting successively equal elements and if the next different element is detected print the count of the former
This works on any number of different elements. Also no second array is needed.
You have the general idea. In addition to your input array, I would suggest three more arrays:
a used array that keeps track of which entries in the input have already been counted.
a value array that keeps track of the distinct numbers in the input array.
a count array that keeps track of how many times a number appears.
For example, after processing the 2 and the 4 in the input array, the array contents would be
input[] = { 2,4,6,7,7,4,4 };
used[] = { 1,1,0,0,0,1,1 }; // all of the 2's and 4's have been used
value[] = { 2,4 }; // unique numbers found so far are 2 and 4
count[] = { 1,3 }; // one '2' and three '4's
Put a print statement in the outer for loop to print value and repetition
for (int i = 0; i < numberOfInts; i++)
{
dub[i] = 0;
for (int y = 0; y < numberOfInts; y++)
{
if (enarray[i] == enarray[y])
{
dub[i]++;
}
}
printf("%d%d",enarray[i], dub[i]);
}
What you're asking for is strange. Normally, I'd create a struct with 2 members, like 'number' and 'count'. But let's try exactly what you're asking for (unidimensional array with each number followed by it's count):
int
i,
numberOfInts = 7,
numberOfDubs = 0,
enarray[7] = {2,4,6,7,7,4,4},
dub[14]; // sizeof(enrray) * 2 => maximum number of dubs (if there are no duplicates)
// For every number on enarray
for(i = 0; i < numberOfInts; i++)
{
int jump = 0;
// Check if we have already counted it
// Only check against pairs: Odds are the dub counter
for(int d = 0; d < numberOfDubs && !jump; d += 2)
{
if(dub[d] == enarray[i])
{
jump = 1;
}
}
// If not found, count it
if(!jump)
{
// Assign the new number
dub[numberOfDubs] = enarray[i];
dub[numberOfDubs + 1] = 1;
// We can begin from 'i + 1'
for(int y = i + 1; y < numberOfInts; y++)
{
if(enarray[i] == enarray[y])
{
dub[numberOfDubs + 1]++;
}
}
// Increment dub's counter by 2: number and it's counter
numberOfDubs += 2;
}
}
// Show results
for(i = 0; i < numberOfDubs; i += 2)
{
printf("%d repeated %d time%s\n", dub[i], dub[i + 1], (dub[i + 1] == 1 ? "" : "s"));
}
I have written a recursive function for my homework to do the following calculation:
For the imput:
1 2 3 4
It should do this:
((1*3)+2) + ((1*4)+3) = 13, thats less than, ((2*4)+3) + ((1*4)+2) = 17, so it returns 13.
In letters it should do this calculation: ((A*C)+B) + ((A*D)+C) and compare it with the other options, in this case there are 2 options: ((B*D)+C) + ((A*D)+C).
In few words. The numbers indicate the number of "screws" on each end of a segment. The segment is always formed by 2 numbers. Segment A {1 2}, B {2 3}, C {3 4}.
The task is to join all the N segments. I must find the "cheapest" way to do it. Every time I join two segments, (A and B for example), I do this:
"bottom screws"of A (1 - the first number) * "top screws"of B (3 - the third number) + "joining screws" (2 - that is the number between).
I have to join them in order, it always must end in order ABCD. But I can choose where to start from. I can join A to B and then AB to C, or i can join B to C and then A to BC. Basically in one of the cases the "cost" will be the lowest and thats the value to return.
For now I have done this, but I got confused:
The *help is a intercalculation array which i use to store the new values gotten in the recursion.
int *help;
The *mezi is a dynamically alocated array defined as:
int *mezi;
And inside it looks like {0,4,1,2,3,4,-1}.
mezi[0] = here is stored the total prize in the recursion.
mezi[1] = here is stored the number of values in the array, 4 for 4 values (3 segments).
mezi[n+2] = the last number (-1), its just an identifier to find out the number of values.
Here's my code:
int findmin(int *mezi, int *pomocny)
{
int i,j,k;
int prize, prizemin, mini, minih;
for (i=3;i<mezi[1];i++) {
prize = mezi[i-1] * mezi[i+1] + mezi[i];
if (i==3) { mini = i; minih = prize; }
if (prize < minih) { mini = i; minih = prize; }
if (mezi[1] > 3){
k=2;
for (j=2;j<mezi[1];j++) {
if (j != mini) help[k] = mezi[j];
k++;
}
help[1] = (mezi[1]-1);
}
help[0] += prize;
findmin(help,help);
}
prizemin = help[0];
return prizemin;
}
Im kinda of a novice, I started using C not long ago and the recursive functions cofuse me a lot. I would reallz appretiate help. Thanks :)
There are quite a few issues with your program logic.
int findmin(int *mezi, int *pomocny)
{
int i,j,k;
int prize, prizemin, mini, minih;
for (i=3;i<mezi[1];i++)
{
prize = mezi[i-1] * mezi[i+1] + mezi[i];
if (i==3) { mini = i; minih = prize; } //This is a redundant test and
//initialization. i == 3 is true only in the first run of the loop. These
//initialization should be done in the loop itself
if (prize < minih) { mini = i; minih = prize; }
if (mezi[1] > 3){ //This is also redundant as mezi[3] is always greater than 3
// otherwise the loop wont run as you check for this in your test expression
k=2;
for (j=2;j<mezi[1];j++) {
if (j != mini) help[k] = mezi[j];
k++;
}
help[1] = (mezi[1]-1);
}
help[0] += prize;
//The only base case test you have is mezi[1]<3 which you should make sure is
// present in your data set
findmin(help,help);
}
prizemin = help[0];
return prizemin;
}