Searching through a 2D array in C goes horible wrong - c

So I have an assignment, and within it is a question that requires you to construct a 2D array with 5 rows and 4 columns, with each of them containing grades. The question requires you to determine how many grades are less than 60, between 60 and 70 and so on (till 100). Thing is when I try to search through it, there should only be 20 total grades, but my solution gives some far fetched number like 60,000 or whatever. I'm at a loss as to what is wrong with my code. I used two for loops to search through the array. Attached is what I've tried. Thanks a ton for any help
#include <stdio.h>
int main(){
double grades[5][4] = {
{69, 58, 95, 78},
{84, 75, 86, 32},
{75, 68, 65, 73},
{99, 54, 24, 88},
{65, 78, 84, 65}
};
int lessthan60, sixtyseventy, seventyeighty, eightyninety, greaterthan90;
for (int r = 0; r < 5; r++){
for (int c=0; c < 4; c++){
if (grades[r][c] < 60){
lessthan60++;
}
else if (grades[r][c] >=60 && grades[r][c] < 70){
sixtyseventy++;
}
else if (grades[r][c] >=70 && grades[r][c] < 80){
seventyeighty++;
}
else if (grades[r][c] >=80 && grades[r][c] < 90){
eightyninety++;
}
else{
greaterthan90++;
}
}
}
printf("Grades less than 60: %d\n", lessthan60);
printf("Grades between 60 and 70: %d\n", sixtyseventy);
printf("Grades between 70 and 80: %d\n", seventyeighty);
printf("Grades between 80 and 90: %d\n", eightyninety);
printf("Grades between 90 and 100: %d\n", greaterthan90);
return 0;
}

These variables having automatic storage duration
int lessthan60, sixtyseventy, seventyeighty, eightyninety, greaterthan90;
are uninitialized and have indeterminate values. You have to initialize them by zero explicitly
int lessthan60 = 0, sixtyseventy = 0, seventyeighty = 0, eightyninety = 0, greaterthan90 = 0;
Also if statements can be written simpler like
if (grades[r][c] < 60){
lessthan60++;
}
else if ( grades[r][c] < 70){
sixtyseventy++;
}
else if ( grades[r][c] < 80){
seventyeighty++;
}
else if ( grades[r][c] < 90){
eightyninety++;
}
else{
greaterthan90++;
}
Also instead of the magic numbers 4 and 5 it is better to use named constants as for example
enum { ROWS = 5, COLS = 4 };
double grades[ROWS][COLS] = {
{69, 58, 95, 78},
{84, 75, 86, 32},
{75, 68, 65, 73},
{99, 54, 24, 88},
{65, 78, 84, 65}
};
//...
for (int r = 0; r < ROWS; r++){
for (int c=0; c < COLS; c++){
//...

This way, you are starting with garbage values.
You need to initialize counters lessthan60, sixtyseventy, seventyeighty, eightyninety, greaterthan90 to zero.

Related

For Loop Not Counting Array Values

Super rookie here. Just doing a little learning before my C course this semester. I found a book practice problem asking to categorize temperature values in an array. Here's everything I have:
// write program to process collection of daily high temps
#include <stdio.h>
int main (void)
{
int temp[26] = {55, 62, 68, 74, 59, 45, 41, 58, 60, 67,
65, 78, 82, 88, 91, 92, 90, 93, 87, 80,
78, 79, 72, 68, 61, 59};
int i;
float sum;
float avg;
int r1, r2, r3; // range 1, range 2, range 3
// Loop to catagorize temperature values
for(i = 0; i <= 26; i++)
{
if (temp[i] <= 60)
{
r1++;
}
else if ((temp[i] > 60) && (temp[i] <= 84))
{
r2++;
}
else
{
r3++;
}
}
printf("\nThe number of cold days are: %d", r1);
printf("\nThe number of pleasant days are: %d", r2);
printf("\nThe number of hot days are: %d", r3);
// Loop to take the average temperature
for (i = 0; i <= 25; i++)
{
sum = sum + temp[i];
avg = sum / i;
}
printf("\nThe average temperature of the set is: %f", avg);
return 0;
}
The average computes correctly, however, the codes is not categorizing the temp values in the array correctly. I just learned arrays yesterday. Can anyone help? Thanks!
You invoked undefined behavior:
1- by using uninitialized variables int r1, r2, r3; float sum; float avg;, you should initialize them as zeros.
2- by accessing if (temp[i] <= 60) in your loop for(i = 0; i <= 26; i++), while size of temp is 26 (should only access 0 - 25).
You should initialize sum, avg, r1, r2, r3 as 0. Also the range of your array is 0-25, so for(i = 0; i <= 26; i++) should be changed to for(i = 0; i <= 25; i++).
// write program to process collection of daily high temps
#include <stdio.h>
int main (void)
{
int temp[26] = {55, 62, 68, 74, 59, 45, 41, 58, 60, 67,
65, 78, 82, 88, 91, 92, 90, 93, 87, 80,
78, 79, 72, 68, 61, 59};
int i;
float sum = 0;
float avg = 0;
int r1 = 0, r2 = 0, r3 = 0; // range 1, range 2, range 3
// Loop to catagorize temperature values
for(i = 0; i <= 25; i++)
{
if (temp[i] <= 60)
{
r1++;
}
else if ((temp[i] > 60) && (temp[i] <= 84))
{
r2++;
}
else
{
r3++;
}
}
printf("The number of cold days are: %d\n", r1);
printf("The number of pleasant days are: %d\n", r2);
printf("The number of hot days are: %d\n", r3);
// Loop to take the average temperature
for (i = 0; i <= 25; i++)
{
sum = sum + temp[i];
avg = sum / i;
}
printf("The average temperature of the set is: %f\n", avg);
return 0;
}
For incrementing the value of a variable you need to initialize the value to the variable. In this case, the variables are r1,r2 & r3. The increment operator increases its value by 1. But if the value is not assigned before, the operator cant finds the value which would be increased.
Here r1++ similar to r1=r1+1.
so it should be initialized like
r1=0,r2=0,r3=0;
r1++; // which means r1=0+1=1
In addition to the existing solutions in the other answers, I propose this solution which introduces you to the concept of programming defensively. In this case I focus on defending against inconsistencies in non-trivial code.
#include <stdio.h>
int main (void)
{
int temp[/* auto */] = {55, 62, 68, 74, 59, 45, 41, 58, 60, 67, 65, 78, 82,
/* newline shows 2*13 */ 88, 91, 92, 90, 93, 87, 80, 78, 79, 72, 68, 61, 59 };
/* in case space allows, this allows humans to grasp the total number and e.g.
notice when the number of initialisers is incorrect; the compiler does not
mind of course */
int i=0; /* this init is paranoid, in case loop setup is unusually without init */
float sum = 0.0f; /* this init is needed, see other answers */
float avg = 0.0f; /* this init is needed, see other answers */
int r1 = 0, r2 = 0, r3 = 0; // range 1, range 2, range 3
size_t length = sizeof(temp)/sizeof(temp[0]); /* avoid need for magic numbers */
// Loop to catagorize temperature values
for(i = 0; i < length; i++) /* avoid need for magic numbers */
{
if (temp[i] <= 60)
{
r1++;
} else if (temp[i] <= 84) /* avoid copy of first treshold */
{
r2++;
} else
{
r3++;
}
}
printf("The number of cold days are: %d\n", r1);
printf("The number of pleasant days are: %d\n", r2);
printf("The number of hot days are: %d\n", r3);
// Loop to take the average temperature
for (i = 0; i < length; i++) /* avoid need for magic number */
{
sum = sum + temp[i];
avg = sum / i;
}
printf("The average temperature of the set is: %f\n", avg);
return 0;
}
You might notice that avoiding magic numbers (using <) and a habit of initialising everything would have prevented both problems discussed and solved in the other answers.
You could also introduce a chance that a human spots a mistake, by outputting a little additional information, assuming of course that it does not conflict with your requirements. In which case the additional output could be created in a way to be removable conveniently for delivery, in a generic way in your team. Without that removal mechanism, this demonstrates "unobtrusive" additional info in output (noticably exaggerated, I admit):
printf("The average temperature of the set of %i temperatures "
"(%i of which have been classified) is: %f\n", length, r1 + r2 + r3, avg);
The special way of aligning {} in if-else constructs is my favorite indentation style. In my opinion, but it is only an opinion, it also is defensive programming, because at least I do spot if-else-trees more easily like that and hence have a better chance of spotting mistakes. Using {} even for single-statement branches is also part of that, it defends against mistakes introduced by adding a statement to a single-statement else branch without {}.
Removing the logically unneeded (temp[i] > 60) && defends against mistakes like
if (temp[i] < 60)
{
r1++;
} else if ((temp[i] > 60) && (temp[i] < 84))
{
r2++;
} else
{
r3++;
}
Because it avoids copying code (in this case the check against treshold 60) and the risk of inconsistencies between the two copies. In this case the mistake I introduces would result in a wrong classification of the edge case temperature 60.

In collatz sequence like 34,17..2,1,print 40 characters per line

From list of collatz sequence that are like 34,17,52,26,13...4,2,1.I want to print 40 characters for each line like "50, 25, 76, 38, 19, 58, 29, 88, 44, 22," will be first line of 40 characters and then next line and should stop when last number are 4, 2, 1
I am unable to stop the program when 4, 2, 1 sequence is encountered.
I have first created the required sequence of numbers. Post that tried to print numbers by for loop with while condition of 1.
int length;
int *ptr;
int i = 50, j = 0;
for (i; i >= 2; )
{
if (i % 2 == 0)
{
i = i / 2;
}
else if (i % 2 != 0)
{
i = (3 * i) + 1;
}
ptr[j] = i;
printf("Total Value: %d, \n", ptr[j]);
j++;
}
for (i = 0; i < 50; )
{
j = 10 + i;
while (i < j)
{
printf("%d, ", ptr[i]);
i++;
if (ptr[i] == 1)
{
break;
}
}
printf("\n");
}
Expected result:
50, 25, 76, 38, 19, 58, 29, 88, 44, 22,
11, 34, 17, 52, 26, 13, 40, 20, 10, 5,
16, 8, 4, 2, 1,
For starters, your code causes a segmentation fault on my machine. You declared ptr as a pointer to an integer int *ptr;, but you are treating it as an array and storing values into it ptr[j] = i;. If you want to put data into an array, then you will either need to malloc a buffer or declare ptr as an array on the stack, i.e., int ptr[SIZE].
A pointer is not a means of storage itself. If you want to have an array for storage, then you need to explicitly allocate an array either on the stack or on the heap.

Finding the first prime number after the entered one

I'm trying to find the first prime number after n, unless entered n is already prime (then the program prints out n and terminates).
Example input:
n = 7
The first prime number is: 7 (Good)
n = 591
The first prime number is: 591 (Not right, 591 is not a prime number)
n = 14
The first prime number is: 15 (This is also false, shouldn't it be 17?)
Where am I making a mistake? It might be an obvious one, but I'm just starting out.
#include <stdio.h>
int main(){
int i = 2, n, m;
printf("n = ");
do
scanf("%d", &n);
while (n < 2);
m = n / 2;
if (n == 2){
printf("The first prime number is: %d", n);
return 0;
}
while ( i <= m ){
if (n % i == 0)
n++;
if (n % i != 0){
printf("The first prime number is: %d", n);
return 0;
} else i++;
}
return 0;
}
Your logic for determining a prime number is wrong.
First of all you should write a function ( not necessarily but it is recommended ) to check whether one number is prime. Here's the code for this function:
int checkPrimeNumber(int n)
{
int j, flag = 1;
for(j=2; j <= n/2; ++j)
{
if (n%j == 0)
{
flag =0;
break;
}
}
return flag;
}
Once you include the function your while loop should loop until if finds the first prime number starting from N using that function. Below is a code for that function.
You can also check this answer here:
https://codereview.stackexchange.com/questions/71212/find-smallest-prime-number-greater-than-given-n
The following two pieces of logic should solve your problem.
int IsPrime(int n)
{
int i;
for( i=2; i <= n/i; i++)
if( n%i == 0 ) return 0;
return 1;
}
This function determines reasonably quickly whether the integer passed in is prime. It stops testing once it has passed the square root of the test integer.
int FirstPrime(int n)
{
while( !IsPrime(n) )
n++;
return n;
}
This function contains the basic logic set out in your problem statement: return the input value, if prime, or failing that the first integer after that value that is prime.
Breaking the code into separate functions makes it much easier to test and to reason about the code.
Checking primality
This is the simpler code that I use for detecting primes:
int isprime(unsigned number)
{
if (number <= 1)
return 0;
if (number == 2 || number == 3)
return 1;
if (number % 2 == 0 || number % 3 == 0)
return 0;
for (unsigned x = 5; x * x <= number; x += 6)
{
if (number % x == 0 || number % (x + 2) == 0)
return 0;
}
return 1;
}
It exploits the fact that all prime numbers larger than 3 have the form 6N±1. It's easy to see why. All the numbers of the forms 6N+0, 6N+2, 6N+4 are clearly divisible by 2 and the numbers of the form 6N+3 are clearly divisible by 3, which leaves only 6N+1 and 6N+5 as possibly prime — and 6N+5 is equivalent to 6(N+1)-1, so the formula 6N±1 covers them properly. For N = 1, 6N±1 yields 5 and 7 which are prime; N = 2 yields 11 and 13 which are prime; N = 3 yields 17 and 19 which are prime; N = 4 yields 23 and 25, of which 23 is prime and 25 is not. All primes bigger than 3 are of the form 6N±1; not all numbers of the form 6N±1 are prime. All this means that the code only checks two divisors out of every six as it steps through the range up to the square root of the number.
I have a more complex variant which knows the primes up to 100, and then goes stepping every 6:
int isprime(unsigned number)
{
if (number <= 1)
return 0;
if (number == 2 || number == 3)
return 1;
if (number % 2 == 0 || number % 3 == 0)
return 0;
static const unsigned int small_primes[] =
{
5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,
53, 59, 61, 67, 71, 73, 79, 83, 87, 89, 91, 97
};
enum { NUM_SMALL_PRIMES = sizeof(small_primes) / sizeof(small_primes[0]) };
for (unsigned i = 0; i < NUM_SMALL_PRIMES; i++)
{
if (number == small_primes[i])
return 1;
if (number % small_primes[i] == 0)
return 0;
}
for (unsigned i = 101; i * i <= number; i += 6)
{
if (number % i == 0 || number % (i + 2) == 0)
return 0;
}
return 1;
}
This is usually marginally faster than the other, but only by a very small amount.
Next prime after
I originally wrote this code for another SO question that was deleted before I posted an answer; it uses another variant of isprime() with a table of primes up to 1013.
/* Inspired by the deleted question SO 5308-6674 */
/* Determine the next prime after a given number */
#include <assert.h>
#include <stdio.h>
#include <limits.h>
#include <stdbool.h>
#define NEXT_PRIME_AFTER /* Avoid unnecessary checks in is_prime() */
#ifdef TEST
static unsigned primes[] = { 2, 3, 5, 7, 11 };
#else
static unsigned primes[] =
{
2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
467, 479, 487, 491, 499, 503, 509, 521, 523, 541,
547, 557, 563, 569, 571, 577, 587, 593, 599, 601,
607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
661, 673, 677, 683, 691, 701, 709, 719, 727, 733,
739, 743, 751, 757, 761, 769, 773, 787, 797, 809,
811, 821, 823, 827, 829, 839, 853, 857, 859, 863,
877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013,
};
#endif /* TEST */
enum { N_PRIMES = sizeof(primes) / sizeof(primes[0]) };
/*
** In the context of next_prime_after(), this function is never called
** upon to validate small numbers - numbers less than primes[N_PRIMES-1]
** are not passed here. In more general contexts, the extra conditions
** in the conditionally compiled code are necessary for accuracy.
*/
static bool is_prime(unsigned p)
{
for (int i = 0; i < N_PRIMES; i++)
{
#ifndef NEXT_PRIME_AFTER
if (p < primes[i])
return false;
if (p == primes[i])
return true;
#endif /* NEXT_PRIME_AFTER */
if (p % primes[i] == 0)
return false;
}
for (unsigned t = primes[N_PRIMES - 1]; t * t <= p; t += 6)
{
if (p % t == 0)
return false;
if (p % (t + 2) == 0)
return false;
}
return true;
}
static unsigned next_prime_after(unsigned start)
{
for (int i = 0; i < N_PRIMES; i++)
{
if (start < primes[i])
return primes[i];
}
for (unsigned x = (start + 1) / 6; x < UINT_MAX / 6; x++)
{
unsigned t = 6 * x - 1;
if (t > start && is_prime(t))
return(t);
t += 2;
if (t > start && is_prime(t))
return(t);
}
return 0;
}
int main(void)
{
assert((primes[N_PRIMES-1]+1) % 6 == 0);
for (unsigned u = 0; u < 100; u++)
printf("%3u => %3u\n", u, next_prime_after(u));
for (unsigned t = 100, u = next_prime_after(t); u < 12345678; t = u)
printf("%3u => %3u\n", t, (u = next_prime_after(t)));
}
Be wary of the isprime() function here. It is tailored to this context and omits checks that would be necessary with a general purpose, standalone prime tester. The next_prime_after() steps through the list of known primes (if you're likely to be dealing with many big possible primes, you might add a test to see whether it is worth stepping through the first loop at all), and then steps through the 6N±1 sequence looking for a prime.
The test code prints the next prime after each number from 0 to 99. Thereafter, it steps through the primes up to 12345701 (which is the first prime after 12345678).
0 => 2
1 => 2
2 => 3
3 => 5
4 => 5
5 => 7
6 => 7
7 => 11
8 => 11
9 => 11
10 => 11
11 => 13
12 => 13
13 => 17
14 => 17
15 => 17
16 => 17
17 => 19
18 => 19
19 => 23
20 => 23
21 => 23
22 => 23
23 => 29
…
95 => 97
96 => 97
97 => 101
98 => 101
99 => 101
100 => 101
101 => 103
103 => 107
107 => 109
109 => 113
113 => 127
127 => 131
…
12345581 => 12345623
12345623 => 12345637
12345637 => 12345643
12345643 => 12345647
12345647 => 12345653
12345653 => 12345701

For Loop Stuck (.C) [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
#include <stdio.h>
int main(void)
{
int ASCII[20] = { 92, 110, 92, 116, 92, 118, 92, 98, 92, 114, 92, 102, 92, 92, 92, 39, 92, 34, 92, 0 };
char *Constants[] = { '\n', '\t', '\v', '\b', '\r', '\f', '\\', '\'', '\"', '\0' };
int Decimal[8] = { 128, 64, 32, 16, 8, 4, 2, 1 };
int Binary[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
int val;
for (int i = 0; i < 20; i++){
val = ASCII[i];
val++; //calculations were one off, so countered mis-calculations with this
for (int i = 0; i < 8; i++){
if (val > Decimal[i]){
val -= Decimal[i];
Binary[i] = 1;
}
}
for (int i = 0; i < 8; i++){
printf("%d", Binary[i]);
}
if ((i + 1) % 2 == 0){
printf("%\n");
}
}
I'm relatively new to C, and I'm trying to create a simple program that converts decimals (constants) to binary values. The loop, however, seems to get stuck after the first iteration like so:
0101110001111110
0111111001111110
0111111001111110
0111111001111110
0111111001111110
0111111001111110
0111111001111110
0111111001111110
0111111101111111
0111111101111111
PLEASE HELP.
Your variable i inside the bigger for loop and the other i's inside the smaller loops are being confused!!
change , use different variables
EDIT :
As David mentioned in the comment bellow : you should also re-initialize your Binary after finishing using them:
for ( j = 0; j < 8; j++){
printf("%d", Binary[j]);
Binary[j] = 0;
}

How to choose the best marks with specified credits in c programming?

I want to make a program to get the weighted average (formula = (mark*(credits corresponds to it))/total credits) from the best(highest) 120 credits module from the following marks and credits (the credits corresponds to the module):
module[12]={48, 77, 46, 82, 85, 43, 49, 73, 65, 48, 47, 51}
credits[12]={60, 20, 20, 20, 10, 20, 10, 10, 10, 20, 20, 10}
What I have done is bubble sort the array, so that the array is sorted by decreasing manner to know which marks is higher, as shown below:
module[12]={85, 82, 77, 73, 65, 51, 49, 48, 48, 47, 46, 43}
credits[12]={10, 20, 20, 10, 10, 10, 10, 60, 20, 20, 20, 20}
And then I need to choose the best 120 credits module from the sorted array so that the weighted average will be maximum, but then I have no idea where to start. =(
Someone help me! Thanks a lot!
EDIT:
I have tried to work out the code myself, and eventually get the following code, it works, but for some special case it stop working =(
float credits=0, result=0;
n=0;
struct{
float credits;
float result;
float n;
float addpoint;
}point;
while (credits < 120){
credits+=credits[n];
result+=(result[n]*credits[n]);
n++;
}
if (credits != 120){
credits -= credits[n-1];
result -= (result[n-1]*credits[n-1]);
point.credits = credits;
point.result = result;
point.n = (n-1)-1;
point.addpoint = n;
again: while (credits < 120){
credits+=credits[n];
result+=(result[n]*credits[n]);
n++;
}
if (credits != 120){
point.credits -= credits[point.n-1];
point.result -= result[point.n-1]*credits[point.n-1];
point.n--;
credits = point.credits;
result = point.result;
n = point.addpoint-1;
goto again;
}
}
EDIT:
Solved. Using knapsack problem code/integer linear programming by the application of glpk
The other way, which is practical for small examples like the one you've got, is to use dynamic programming. One can build up a table of "optimal score if you use the first k subjects, and want credits to add up to T". The code's a bit messy because C doesn't make it particularly easy to have dynamically sized 2d arrays, but here's a solution. Probably your professor was expecting something along these lines.
A small note, I divided all the credits (and the target credits of 120) by 10 because the common factor was redundant, but the code works just fine without that (it'll just use a tad more memory and time).
#include <stdio.h>
#include <stdlib.h>
int max(int a, int b) {
return a > b ? a : b;
}
#define GET(t, i, j, n) ((t)[(i) * (n + 1) + j])
// optimize_marks takes arrays creds and marks (both of length n),
// and finds a subset I of 0..(n-1) that maximizes
// sum(i in I)creds[i]*marks[i], such that sum(i in I)creds[i] = total.
void optimize_marks(size_t n, int *creds, int *marks, int total) {
// tbl[k * (total + 1) + T] stores the optimal score using only the
// first k subjects for a total credit score of T.
// tbl[n * (total + 1) + total] will be the final result.
// A score of -1 means that the result is impossible.
int *tbl = malloc((n + 1) * (total + 1) * sizeof(int));
for (int i = 0; i <= n; i++) {
for (int T = 0; T <= total; T++) {
if (i == 0) {
// With 0 subjects, the best score is 0 if 0 credits are
// required. If more than 0 credits are required, the result
// is impossible.
GET(tbl, i, T, total) = -(T > 0);
continue;
}
// One way to get T credits with the first i subjects is to
// get T credits with the first (i-1) subjects.
GET(tbl, i, T, total) = GET(tbl, i - 1, T, total);
// The other way is to use the marks for the i'th subject
// and get the rest of the credits with the first (i-1) subjects.
// We have to check that it's possible to use the first (i-1) subjects
// to get the remainder of the credits.
if (T >= creds[i-1] && GET(tbl, i - 1, T - creds[i-1], total) >= 0) {
// Pick the best of using and not using the i'th subject.
GET(tbl, i, T, total) = max(
GET(tbl, i, T, total),
GET(tbl, i - 1, T - creds[i-1], total) + marks[i-1] * creds[i-1]);
}
}
}
int T = total;
for (int i = n; i > 0; i--) {
if (GET(tbl, i - 1, T, total) < GET(tbl, i, T, total)) {
printf("%d %d %d\n", i, creds[i-1], marks[i-1]);
T -= creds[i-1];
}
}
}
int main(int argc, char *argv[]) {
int creds[] = {6, 2, 2, 2, 1, 2, 1, 1, 1, 2, 2, 1};
int marks[] = {48, 77, 46, 82, 85, 43, 49, 73, 65, 48, 47, 51};
optimize_marks(12, creds, marks, 12);
return 0;
}
The program gives the solution as the ILP program:
12 1 51
11 2 47
10 2 48
9 1 65
8 1 73
5 1 85
4 2 82
2 2 77
This is an integer linear programming problem. You want to find a vector [x1 x2 x3 ... x12] where each of the x's is either 0 or 1, such that sum(x[i] * cred[i]) = 120 and that sum(x[i] * cred[i] * marks[i]) is maximised.
There's a large body of research in how to solve such problems, but there's existing solvers out there and ready for you to use and using them is going to save you a vast amount of time over coding a solver up yourself.
Here's a module file for glpk, a free linear programming and integer linear programming solver. You can run it by installing glpk, saving this to a file then running glpsol -m <filename>
set I := 1..12;
var x{I} binary;
param cred{I};
param marks{I};
maximize s:
sum{i in I}(x[i] * cred[i] * marks[i]);
s.t. totalcreds: sum{i in I}(x[i] * cred[i]) = 120;
solve;
printf {i in I} "%d: %d %d %d\n", i, x[i], cred[i], marks[i];
data;
param cred := 1 60, 2 20, 3 20, 4 20, 5 10, 6 20, 7 10, 8 10, 9 10, 10 20, 11 20, 12 10;
param marks := 1 48, 2 77, 3 46, 4 82, 5 85, 6 43, 7 49, 8 73, 9 65, 10 48, 11 47, 12 51;
end;
The output is this:
1: 0 60 48
2: 1 20 77
3: 0 20 46
4: 1 20 82
5: 1 10 85
6: 0 20 43
7: 0 10 49
8: 1 10 73
9: 1 10 65
10: 1 20 48
11: 1 20 47
12: 1 10 51
That is, you should pick courses 2, 4, 5, 8, 9, 10, 11, 12 (ie: the courses with a '1' by them).
You should probably start by isolating all the combinaisons of credits[] elements whose sum equals 120 and store them before calculating all the means.
It would look like that :
// test for all possible combinaisons :
// [0] + [1] + [2]..., [1] + [0] + [2]...
// starting point on the array : n
while(n < 12){
// if the sum isnt equal to 120 and
// we havent covered all the array yet
if(temp < 120 && i < 12){
// if i is different from the starting point
if(i < 11 && i != n){
i++;
temp += credits[i];
// store i
}
}
if(temp >120 && i < 11){
temp -= credits[i];
// remove i
i++;
}
if(temp == 120){
// starting point ++
n++;
}
}
It's not optimal, but it could work.

Resources