I try to work with a contiguous block of memory, more over I try to create an array who's dimensions are not known at compile time (before C99) so no variable-length arrays are involved here.
I came with the following:
#include <stdio.h>
#include <stdlib.h>
int main(void){
unsigned int row, col,i, j, k;
int l = 0;
printf("Give the ROW: ");
if ( scanf("%u",&row) != 1){
printf("Error, scanf ROW\n");
exit(1);
}
printf("Give the COL: ");
if ( scanf("%u",&col) != 1){
printf("Error, scanf COL\n");
exit(2);
}
int *arr = malloc(sizeof *arr * row * col); /* This doesn't compile with `-pedantic` */
if(arr == NULL){
printf("Error, malloc\n");
exit(3);
}
for ( i = 0; i < row ; i++){
for ( j = 0 ; j < col ; j++){
arr[i * col + j] = l;
l++;
}
}
for (k = 0 ; k < (row * col) ; k++){
printf("%d ",arr[k]);
}
free(arr);
}
Which give's me the following:
Give the ROW: 5
Give the COL: 5
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Now I have a Questions:
Is this the right approach?
You have a hidden error in this line:
arr[i * row + j] = k;
The correct index calculation is
arr[i * col + j] = k;
The reason that you don't notice that problem is that row and col have the same value in the code. If, for example, you set row to 6 and col to 3, the error will be obvious. You will allocate space for 18 ints, but when i is 5 and j is 2, the code will try to access location [5*6 + 2] which is off the end of the array, and will result in undefined behavior.
Here's how the address calculation works. The drawing below shows how a 2D array (row=6 and col=3) is actually laid out in memory. Note that the number of items on each row is equal to the number of columns in the array. So the starting index for each row is a multiple of the number of columns. In this example, since the number of columns is 3, the rows start at indexes 0,3,6,9,... So given an element at index [i][j] in the 2D array, the index in the 1D array is i*col + j.
The approach is okay. And the dimensions are known at compile time.
The reason for getting 15 is that arr it represents the base address so when you add 15 to arr it will give you the address of block containing 15 and later on de-referencing you will get 15.
If you don't know the number of dimensions ahead of time (1, 2, 3, or more dimensions), then this is the only approach you have available. If you know the number of dimensions, but not their values, and you don't have VLAs available, again, this is the only approach you have available.
Because I am bored out of my freaking skull from writing documentation, I womped up this quick and dirty prototype to demonstrate how you can map a 1D array onto arrays of different numbers of dimensions:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
/**
* Compute the offset into a 1D array based on a set of dimensions
* and indices, and return the element at that offset. You must pass
* at least as many indices as number of dimensions; any extra indices
* will not be processed.
*
* Inputs:
* a -- 1D array of data
* ndims -- number of dimensions to map array onto
* dims -- dimension sizes
* ... -- index values
*
* Outputs: none
*
* Returns: value at desired index
*/
int access( const int * restrict a, size_t ndims, const size_t * restrict dims, ... )
{
va_list ap;
va_start( ap, dims ); point to first index value in argument list
size_t idx = 0;
/**
* To find the right index for a given number of dimensions,
* we need to compute
*
* d0 x d1: i * d1 + j
* d0 x d1 x d2: i * d1 * d2 + j * d1 + k
* d0 x d1 x d2 x d3: i * d1 * d2 * d3 + j * d1 * d2 + k * d1 + l
*
* The loop below computes these as
*
* i * d1 + j
* (i * d2 + j) * d1 + k
* (((i * d3 + j) * d2) + k) * d1 + l
*
* etc.
*/
for ( size_t i = 1; i < ndims; i++ )
{
idx += va_arg( ap, size_t ); // get next index argument and advance ap
idx *= dims[i];
}
idx += va_arg( ap, size_t );
va_end( ap );
return a[idx];
}
int main( void )
{
int test[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
size_t dims2x5[] = {2, 5}; // for mapping test onto a 2x5 array
size_t dims3x3[] = {3, 3}; // for mapping test onto a 3x3 array
size_t dims2x2x2[] = {2, 2, 2}; // for mapping test onto a 2x2x2 array
for ( size_t i = 0; i < dims2x5[0]; i++ )
for ( size_t j = 0; j < dims2x5[1]; j++ )
printf( "test[%zu][%zu] = %d\n", i, j, access( test, 2, dims2x5, i, j ) );
for ( size_t i = 0; i < dims3x3[0]; i++ )
for ( size_t j = 0; j < dims3x3[1]; j++ )
printf( "test[%zu][%zu] = %d\n", i, j, access( test, 2, dims3x3, i, j ) );
for ( size_t i = 0; i < dims2x2x2[0]; i++ )
for ( size_t j = 0; j < dims2x2x2[1]; j++ )
for ( size_t k = 0; k < dims2x2x2[2]; k++ )
printf( "test[%zu][%zu][%zu] = %d\n", i, j, k, access( test, 3, dims2x2x2, i, j, k ));
return 0;
}
And the output:
test[0][0] = 0
test[0][1] = 1
test[0][2] = 2
test[0][3] = 3
test[0][4] = 4
test[1][0] = 5
test[1][1] = 6
test[1][2] = 7
test[1][3] = 8
test[1][4] = 9
test[0][0] = 0
test[0][1] = 1
test[0][2] = 2
test[1][0] = 3
test[1][1] = 4
test[1][2] = 5
test[2][0] = 6
test[2][1] = 7
test[2][2] = 8
test[0][0][0] = 0
test[0][0][1] = 1
test[0][1][0] = 2
test[0][1][1] = 3
test[1][0][0] = 4
test[1][0][1] = 5
test[1][1][0] = 6
test[1][1][1] = 7
This isn't pretty - access( a, 3, dims2x2x2, i, j, k ) doesn't exactly read as easily as a[i][j][k]. With some additional levels of abstraction you could clean that up a bit, but it's always going to feel a bit awkward. And naturally you sacrifice some performance. But, if you need to be able to map a 1D array onto an arbitary-sized N-dimensional array where you don't even know the number of dimensions ahead of time, this is a possible solution.
Related
I have a text file with a large matrix (56*10000). But here is a sample.
A B C D
1 3 4 5
3 5 6 10
2 2 6 11
3 2 3 38
3 3 1 19
I have a code which can read the file and also print it. I have two problems.
I can't seem to find a way to print a particular column. For example in MATLAB, if we want to print the second column we indicate it like [:,2].
Is there way where I can access the column by a particular name. For example, since these columns are named A B C D, if I want to print the second column, I just have to say, if case in B, print (B) and it has to print,
3
5
2
2
3
Here is the code that I have.
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE * fp;
int M = 5, N = 4;
char filter[1024] ;
double *Z_BS = (double *)malloc(M * N * sizeof(double));
fp = fopen("test.txt","r");
if (fp == NULL)
{
exit(1);
}
fgets(filter,1024,fp);
for (int rows = 0; rows < M; rows++)
{
for (int cols = 0; cols < N; cols++)
{
fscanf(fp, "%lf", Z_BS);
printf("%lf\t", *Z_BS);
}
printf("\n");
if (feof(fp))
{
break;
}
}
}
In C there is no way like matlab, but with the help of below idea you can generate the required offset
offset = row_size*i + column_number
lets say there are five 5 rows and 5 columns and you want to access 3 column.
A B C D E
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
when i = 0, 5*0+3 = 3
when i = 1, 5*1+3 = 8
when i = 2, 5*2+3 = 13
when i = 3, 5*3+3 = 18
when i = 4, 5*4+3 = 23
NOTE: check for EOF always or the offset is valid before using, you should not access anything beyond the file.
Unrelated, but if you just want to print the values, there's no need to allocate memory.
Using a local variable is enough
for (int rows = 0; rows < M; rows++) {
for (int cols = 0; cols < N; cols++) {
double Z_BS;
fscanf(fp, "%lf", &Z_BS);
printf("%lf\t", Z_BS);
}
printf("\n");
if (feof(fp)) {
break;
}
}
To print just one column, you can simply use the col variable, say print the second column
for (int cols = 0; cols < N; cols++) {
double Z_BS;
fscanf(fp, "%lf", &Z_BS);
if (cols == 1)
printf("%lf\t", Z_BS);
}
It says cols == 1, because the loop starts at 0 (first column = 0, second column = 1, ...).
To print by column name, don't skip the first row, but compare the name, e.g.
char colname[] = "B";
int colnum;
// Scan header row
for (int cols = 0; cols < N; cols++) {
char current[51];
fscanf(fp, "%.50s", current);
if (strcmp(current, colname) == 0) {
colnum = cols;
break;
}
}
and later while printing
if (cols == colnum)
printf("%lf\t", Z_BS);
My problem in general is multiplying polynomials with linked lists. I came to the conclusion that it's better to store all the products in a matrix and then add up their diagonals and semi-diagonals.
For example: Given the matrix 4x4
6,12,18,24
15,30,48,60
9,18,27,30
21,42,63,81
i would like as result: 6 27 57 111 129 93 81
and the results come from:
1. 6
2. 27 -> 12 + 15
3. 57 -> 18 + 30 + 9
4. 111 -> 24 + 48 + 18 + 21
5. 129 -> 60 + 27 + 42
6. 93 -> 30 + 63
7. 81
This is my function, receives two linked lists to which it then multiplies the coefficients that have equal degree and transfers them to a matrix of nxm
int* multi(List* L1, List* L2){
int n, m, i,j;
List* ret;
ret = l_new(); //Creates a new list
//AUX POINTERS
node* n1;
node* n2;
//Asign pointers to the head of the lists
n1 = L1->first;
n2 = L2->first;
n = L1->size;
m = L2->size;
double arr[n][m];
//Fill matrix
for(i=0; i<L1->size; i++){
for(j=0; j<L2->size; j++){
arr[i][j] = n1->coef * n2->coef;
n2 = n2->next;
if(n2 == NULL){n2 = L2->first; n1 = n1->next;}
}
}
}
//FIX RETURN
return 0;
}
The elements in the k-th diagonal that you are interested have in common that:
row + column = k
In total, there are n + m - 1 diagonals, where n and m are the dimensions of the matrix. This can be turned into the following algorithm:
coefficients = new list of n + m - 1 elements, initialized to 0
for(int col = 0; col < n; ++col)
for(int row = 0; row < m; ++row)
{
int k = row + col;
coefficients[k] += arr[column][row];
}
I have the following matrix:
1 4 5
5 7 6
5 8 8
I want to find the minimum value of line 1 and subtract from all values of the same line. The same thing for line 2 and 3. The minimum value of line 1 is 1, line 2 is 5 and line 3 is 5. So I subtract 1 from all values of line 1, subtract 5 from all values in line 2 and subtract 5 from all values in line 3.
0 3 4
0 2 1
0 3 3
My matrix is called "a":
min = a[0][0] \\\ min = minimum value
for (k = 0; k < 3; k++) {
for (l = 1; l < 3; l++) {
if (a[k][l] < min)
min = a[k][l - 1];
}
for (l = 0; l < 3; l++) {
a[k][l] = a[k][l] - min;
}
min = a[k+1][0];
}
For k = 0, the value a[k+1][0] = 5 is changing to 4. Why is that?
EDIT: I declared the array as:
a[0][0] = 1;
a[0][1] = 4;
a[0][2] = 5;
a[1][0] = 5;
a[1][1] = 7;
a[1][2] = 6;
a[2][0] = 5;
a[2][1] = 8;
a[2][2] = 8;
Following Kresimir I changed the code to:
for (k = 0; k < 3; k++) {
min = 10000;
for (l = 0; l < 3; l++) {
if (a[k][l] < min)
min = a[k][l];
}
for (l = 0; l < 3; l++) {
a[k][l] = a[k][l] - min;
}
}
To print the matrix:
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++) {
printf("a[%d][%d] = %d\n", i, j, a[i][j]);
}
}
But the output is:
a[0][0] = 0
a[0][1] = 3
a[0][2] = 0
a[1][0] = 0
a[1][1] = 3
a[1][2] = 0
a[2][0] = 0
a[2][1] = 0
a[2][2] = 3
When k = 0, the first line is changed correctly and the rest is kept the same as they should, when k = 1, all lines are changed wrong to the above.
When approaching any bit of coding, it generally helps to break your coding tasks down into a series of individual steps -- that then provide a road-map to follow as you begin actual coding. You can type the steps out in a separate editor window, (or what I find just as helpful is an 8 1/2 x 11 sheet of paper and pencil).
Think through what your code must do and write it down, e.g.
loop over all rows in the matrix (a/k/a the 2D array of int);
loop over all column values to find the minimum in each row; and finally
loop over all column values (again) subtracting the minimum from each value.
You don't have to get it perfect the first time, now look again at the steps you have written and determine if there are any constraints you must impose.
(Here, yes, you must determine the minimum by examining each value in a row before you can begin subtracting the minimum from each value -- this necessitates at least two loops over the column values. Further, you must also reset or re-initialize your min variable so that it holds the minimum for the current row -- not the minimum from the last row that just happened to be less than this one. Use the re-initialization requirement to make a logical choice for the scope within which each variable should be declared)
Now with your steps refined with any constraints you must impose, you can logically lay out your code (keeping in mind that you must always protect against reading or writing beyond your array bounds, etc.) With the benefit of a good outline, you know you will need one outer loop that loops over all rows, and then two inner loops that (a) find the minimum, and (b) subtract that from all values in that row. You could do something similar to:
#include <stdio.h>
#include <limits.h> /* for INT_MAX, INT_MIN */
#define ASZ 3 /* if you need a constant, define one (or more), a size */
int main (void) {
int a[][ASZ] = {{ 1, 4, 5 }, { 5, 7, 6 }, { 5, 8, 8 }};
puts ("Original matrix:"); /* output original matrix */
for (int row = 0; row < ASZ; row++) {
for (int col = 0; col < ASZ; col++)
printf (" %2d", a[row][col]);
putchar ('\n');
}
puts ("\nModified matrix:"); /* subtract row-min from each element */
for (int row = 0; row < ASZ; row++) { /* loop over rows */
int min = INT_MAX; /* declare min = INT_MAX */
for (int col = 0; col < ASZ; col++) /* loop over column vals */
if (a[row][col] < min) /* find row-min value */
min = a[row][col];
for (int col = 0; col < ASZ; col++) { /* loop over column vals */
a[row][col] -= min; /* subtract row-min value */
printf (" %2d", a[row][col]); /* output new value */
}
putchar ('\n');
}
}
Example Use/Output
$ ./bin/mtrx_subtract_rowmin
Original matrix:
1 4 5
5 7 6
5 8 8
Modified matrix:
0 3 4
0 2 1
0 3 3
There is no magic to it, it just takes approaching each problem in a systematic way. Doing it often enough, it gets easier each time. Pay attention to where each variable was declared (or constant defined) and understand why. Let me know if you have any further questions.
If you want to find the minimum for each line, you need to initialise it for each line, not only once.
for (k = 0; k < 3; k++) {
min = a[k][0];
...
You were only searching for the minimum so far.
Whenever I'm looking for a minimum, I set min to positive infinity (nothing can be larger than that - you don't have to do it, but it makes for a nicer code, in my opinion).
Alternatively, you can use min = Math.min(...a[k]); instead of that entire first for loop (will not work on IE, though).
Also, keep in mind that indices go from 0 to 2. Also, check the order of k and l (depending on how you implement the rows and columns of the matrix).
let k, l, min;
let a=[[1, 4, 5],
[5, 7, 6],
[5, 8, 8]];
for (k = 0; k < 3; k++) {
min = +Infinity;
for (l = 0; l < 3; l++) {
if (a[k][l] < min)
min = a[k][l];
}
for (l = 0; l < 3; l++) {
a[k][l] = a[k][l] - min;
}
}
console.log(a);
This question already has answers here:
How to create a random permutation of an array?
(3 answers)
Closed 6 years ago.
i am doing a homework. i put rand function in a loop.
int counter = 1;
while ( counter <= 10 ){
variable1 = rand() % 5 + 1;
printf("%d", variable);
counter = counter + 1;
In this code, rand function assigns different value to variable called variable1 but sometimes it assigns same value because range of rand function is narrow. how can i perform that rand function assign different number to variable at the time when loop returns every time.
While rand() is not the greatest random function it should do the trick for many jobs and certainly for most homework. It is perfectly valid to have the same number returned twice in a row from a random function -- as the function should not have any memory of what values were previously returned.
The best way to understand this, is with an example of a coin-toss. Every coin toss is random, and the coin has no memory of the previous toss, so it is possible to flip a coin 32 times in a row and they all comes up head -- if every coin toss is a bit in a 32 bit integer you have created the binary value of integer zero.
However human tend to think (intuition) that having the same value returned more than once is "wrong" for a random function -- but our intuition is wrong on this account.
If you for some reason do want to not repeat the number from one loop to the next, then you will need to program that regardless of which random functions you use -- since any random function would be capable of returning the same values twice.
So something like this would do it;
int counter = 1;
int prevValue = -1;
while ( counter <= 10 ){
do {
variable1 = rand();
} while (variable1 == prevValue);
prevValue = variable1;
variable1 = variable1 % 5 + 1;
printf("%d", variable);
counter = counter + 1;
}
Note that this is still capable of printing the same value twice, since 10 and 15 would be different values before the %5 but would be the same after. If you want the %5 to be taken into account, so the printf never print the same value twice in a row, you would need to move the %5 inside the loop.
In your code snippet i can't find which instruction is the last one inside while. If you want to get different numbers every program run you should use srand() function before while.
But as you mentioned before. Your range (1 - 5) is to narrow to get 10 unique values every time.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void) {
int counter = 1;
int variable1 = 0;
srand(time(NULL));
while ( counter <= 10 ) {
variable1 = rand() % 5 + 1;
printf("%d ", variable1);
counter = counter + 1;
}
putchar('\n');
return 0;
}
how can i perform that rand function assign different number to variable at the time when loop returns every time?
I take this to mean OP does not want to generate the same number twice in a row.
On subsequent iterations, use %(n-1)
int main(void) {
int counter;
int variable;
for (counter = 1; counter <= 10; counter++) {
// First time in loop
if (counter <= 1) {
variable = rand() % 5 + 1;
} else {
int previous = variable;
variable = rand() % (5 - 1) + 1;
if (variable >= previous) variable++;
}
printf("%d\n", variable);
}
return 0;
}
In order to generate a unique list of random numbers, you must check each number generated against the list of numbers previously generated to insure there is no duplicate. The easiest way is to store your previously generated numbers in an array to check against. Then you simply iterate over the values in the array, and if your most recent number is already there, create a new one.
For example, you can use a simple flag to check if your are done. e.g.
while (counter < MAXI){
int done = 0;
while (!done) { /* while done remains 0 (not done) */
done = 1;
tmp = rand() % MAXI + 1; /* generate radom number */
for (i = 0; i < counter; i++) /* check again previous */
if (tmp == array[i]) /* if num already exists */
done = 0; /* set as (not done) */
}
array[counter++] = tmp; /* assign random value */
}
Or you can use the old faithful goto to do the same thing:
while (counter < MAXI) {
gennum:
tmp = rand() % MAXI + 1;
for (i = 0; i < counter; i++)
if (tmp == array[i])
goto gennum;
array[counter++] = tmp;
}
Whichever makes more sense to you. Putting together a full example, you could do:
#include <stdio.h>
#include <stdlib.h> /* for rand */
#include <time.h> /* for time */
enum { MAXI = 10 };
int main (void) {
int array[MAXI] = {0}, counter = 0, i, tmp;
srand (time (NULL)); /* initialize the semi-random number generator */
while (counter < MAXI){
int done = 0;
while (!done) { /* while done remains 0 (not done) */
done = 1;
tmp = rand() % MAXI + 1; /* generate radom number */
for (i = 0; i < counter; i++) /* check again previous */
if (tmp == array[i]) /* if num already exists */
done = 0; /* set as (not done) */
}
array[counter++] = tmp; /* assign random value */
}
for (i = 0; i < MAXI; i++)
printf (" array[%2d] = %d\n", i, array[i]);
return 0;
}
(note: the number your mod (%) the generated number by must be equal to or greater than the number of values you intend to collect -- otherwise, you cannot generate a unique list.)
Example Use/Output
$ ./bin/randarray
array[ 0] = 8
array[ 1] = 2
array[ 2] = 7
array[ 3] = 9
array[ 4] = 1
array[ 5] = 4
array[ 6] = 3
array[ 7] = 10
array[ 8] = 6
array[ 9] = 5
A Shuffled Sequence
Given the discussion in the comments, a good point was raised concerning whether your goal was to create unique set of random numbers (above) or a random set from a sequence of numbers (e.g. any sequence, say 1-50 in shuffled order). In the event you are looking for the latter, then an efficient method to create the shuffled-sequence is using a modified Fisher-Yates shuffle knows as The "inside-out" algorithm.
The algorithm allows populating an uninitialized array with a shuffled sequence from any source of numbers (whether the source can be any manner of generating numbers). Essentially, the function will swap the values within an array at the current index with the value held at a randomly generated index. An implementation would look like:
/** fill an uninitialized array using inside-out fill */
void insideout_fill (int *a, int n)
{
int i, val;
for (i = 0; i < n; i++) {
val = i ? randhq (i) : 0;
if (val != i)
a[i] = a[val];
a[val] = i; /* i here can be any source, function, etc.. */
}
}
(where randhq is any function that generates a random value (0 <= val < n))
A short example program that uses the function above to generate a shuffled array of value from 0 - (n-1) is shown below. The example generates a shuffled sequence of values in array using the inside-out algorithm, and then confirms the sequence generation by sorting the array:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void insideout_fill (int *a, int n);
int randhq (int max);
void prnarray (int *a, size_t n, size_t strd, int wdth);
int intcmp (const void *a, const void *b);
int main (int argc, char **argv) {
srand (time (NULL));
int arrsz = argc > 1 ? (int)strtol (argv[1], NULL, 10) : 50;
int array[arrsz];
insideout_fill (array, arrsz);
printf ("\n array initialized with inside-out fill:\n\n");
prnarray (array, arrsz, 10, 4);
qsort (array, arrsz, sizeof *array, intcmp);
printf ("\n value confirmation for inside-out fill:\n\n");
prnarray (array, arrsz, 10, 4);
return 0;
}
/** fill an uninitialized array using inside-out fill */
void insideout_fill (int *a, int n)
{
int i, val;
for (i = 0; i < n; i++) {
val = i ? randhq (i) : 0;
if (val != i)
a[i] = a[val];
a[val] = i; /* i here can be any source, function, etc.. */
}
}
/** high-quality random value in (0 <= val <= max) */
int randhq (int max)
{
unsigned int
/* max <= RAND_MAX < UINT_MAX, so this is okay. */
num_bins = (unsigned int) max + 1,
num_rand = (unsigned int) RAND_MAX + 1,
bin_size = num_rand / num_bins,
defect = num_rand % num_bins;
int x;
/* carefully written not to overflow */
while (num_rand - defect <= (unsigned int)(x = rand()));
/* truncated division is intentional */
return x/bin_size;
}
/** print array of size 'n' with stride 'strd' and field-width 'wdth' */
void prnarray (int *a, size_t n, size_t strd, int wdth)
{
if (!a) return;
register size_t i;
for (i = 0; i < n; i++) {
printf (" %*d", wdth, a[i]);
if (!((i + 1) % strd)) putchar ('\n');
}
}
/** qsort integer compare */
int intcmp (const void *a, const void *b)
{
return *((int *)a) - *((int *)b);
}
Example Use/Output
$ ./bin/array_io_fill
array initialized with inside-out fill:
40 15 35 17 27 28 20 14 32 39
31 25 29 45 4 16 13 9 49 7
11 23 8 33 48 37 41 34 19 38
24 26 47 44 5 0 6 21 43 10
2 1 18 22 46 30 12 42 3 36
value confirmation for inside-out fill:
0 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
Look it over and let me know if you have any questions.
So I have been trying to do a variant of the subset sum problem, which I want to do using dynamic programming. So what I am aiming for is for example, to have an input of
m = 25 // Target value
n = 7 // Size of input set
and the input set to be for example {1, 3, 4, 6, 7, 10, 25}. So the wanted output would be something like
{1, 3, 4, 7, 10} and {25}.
Here is the code
#include <stdio.h>
#include <stdlib.h>
int main()
{
// Get input sequence
int n = 7; // Size of input set
int m = 25; // Target value
int *S; // Input set
int **C; // Cost table
int i,j,potentialSum,leftover;
S=(int*) malloc((n+1)*sizeof(int));
C=malloc((m+1)*sizeof(int*));
for (int rows = 0; rows<=m; rows++) {
C[rows] = malloc((m+1)*sizeof(int));
}
if (!S || !C)
{
printf(" FAILED %d\n",__LINE__);
exit(0);
}
S[0] = 0;
S[1] = 1;
S[2] = 3;
S[3] = 4;
S[4] = 6;
S[5] = 7;
S[6] = 10;
S[7] = 25;
// Initialize table for DP
C[0][0]=0; // DP base case
// For each potential sum, determine the smallest index such
// that its input value is in a subset to achieve that sum.
for (potentialSum=1; potentialSum<=m; potentialSum ++)
{
for (j=1;j<=n;j++)
{
leftover=potentialSum-S[j]; // To be achieved with other values
if (leftover<0) // Too much thrown away
continue;
if (C[leftover][0] == (-1)) // No way to achieve leftover
continue;
if (C[leftover][0]<j) // Indices are included in
break; // ascending order.
}
C[potentialSum][0]=(j<=n) ? j : (-1);
}
// Output the input set
printf(" i S\n");
printf("-------\n");
for (i=0;i<=n;i++)
printf("%3d %3d\n",i,S[i]);
// Output the DP table
printf("\n\n i C\n");
printf("-------\n");
for (i=0;i<=m;i++)
printf("%3d %3d\n",i,C[i][0]);
if (C[m][m]==(-1))
printf("No solution\n");
else
{
printf("\n\nSolution\n\n");
printf("(Position) i S\n");
printf("------------------\n");
for (i=m;i>0;i-=S[C[i][0]])
printf(" %3d %3d\n",C[i][0],S[C[i][0]]);
}
}
This will output the following
i S
-------
0 0
1 1
2 3
3 4
4 6
5 7
6 10
7 25
i C
-------
0 0
1 1
2 -1
3 2
4 2
5 3
6 4
7 3
8 3
9 4
10 4
11 4
12 5
13 4
14 4
15 5
16 5
17 5
18 5
19 6
20 5
21 5
22 6
23 6
24 6
25 6
Solution
(Position) i S
------------------
6 10
5 7
3 4
2 3
1 1
Program ended with exit code: 0
My problem is that I can only output one solution, and that is the solution that needs the smaller values and goes up to 25, so when 25 is used it isn't in the solution. The C array in the code is a 2-D array, since I thought I could maybe do another backtrace while computing the first one? I couldn't figure out how to do so, so I left C[i][0] fixed to the first column, just to demonstrate a single solution. Any tips in the right direction would be greatly appreciated. I found a solution using Python, but the problem is solved recursively, which I don't think helps me, but that code is here.
Thanks for all the help in advance.
I did not fully understand your code. But here is a C code which finds all the subsets that sum to target.
#include <stdio.h>
int a[] = { 0, 1, 3, 4, 6, 7, 10, 25 }; //-- notice that the input array is zero indexed
int n = 7;
int target = 25;
int dp[8][26];
int solutions[1 << 7][8]; //-- notice that the number of subsets could be exponential in the length of the input array a.
int sz[1 << 7]; //-- sz[i] is the length of subset solutions[i]
int cnt = 0; //-- number of subsets
void copy(int srcIdx, int dstIdx){
int i;
for (i = 0; i < sz[srcIdx]; i++)
solutions[dstIdx][i] = solutions[srcIdx][i];
sz[dstIdx] = sz[srcIdx];
}
//-- i, and j are indices of dp array
//-- idx is the index of the current subset in the solution array
void buildSolutions(int i, int j, int idx){
if (i == 0 || j == 0) return; // no more elements to add to the current subset
if (dp[i - 1][j] && dp[i - 1][j - a[i]]){ // we have two branches
cnt++; // increase the number of total subsets
copy(idx, cnt); // copy the current subset to the new subset. The new subset does not include a[i]
buildSolutions(i - 1, j, cnt); //find the remaining elements of the new subset
solutions[idx][sz[idx]] = a[i]; // include a[i] in the current subset
sz[idx]++; // increase the size of the current subset
buildSolutions(i - 1, j - a[i], idx); // calculate the remaining of the current subset
}
else if (dp[i - 1][j - a[i]]){ // we only have one branch
solutions[idx][sz[idx]] = a[i]; // add a[i] to the current subset
sz[idx]++;
buildSolutions(i - 1, j - a[i], idx); // calculate the remaining of the current subset
}
else buildSolutions(i - 1, j, idx); // a[i] is not part of the current subset
}
int main(){
int i, j;
// initialize dp array to 0
for (i = 0; i <= n; i++)
for (j = 0; j <= target; j++) dp[i][j] = 0;
//-- filling the dp array
for (i = 0; i <= n; i++)
dp[i][0] = 1;
for (i = 1; i <= n; i++){
for (j = 1; j <= target; j++){
if (j < a[i])
dp[i][j] = dp[i - 1][j];
else
dp[i][j] = dp[i - 1][j] || dp[i - 1][j - a[i]];
}
}
//-- building all the solutions
for (i = 0; i < sizeof(sz); i++) sz[i] = 0; //-- initializing the sz array to 0
buildSolutions(n, target, 0);
//-- printing all the subsets
for (i = 0; i <= cnt; i++){
for (j = 0; j < sz[i]; j++){
printf("%d ", solutions[i][j]);
}
printf("\n");
}
}
If you have any questions about the code, do not hesitate to ask.