Summation of all proper divisors - c

I have solved a question that says:
Given a natural number n (1 <= n <= 500000), please output the summation of all its proper divisors.
Definition: A proper divisor of a natural number is the divisor that is strictly less than the number.
e.g. number 20 has 5 proper divisors: 1, 2, 4, 5, 10, and the divisor summation is: 1 + 2 + 4 + 5 + 10 = 22.
Input
An integer stating the number of test cases (equal to about 200000), and that many lines follow, each containing one integer between 1 and 500000 inclusive.
Output
One integer each line: the divisor summation of the integer given respectively.
Example
Sample Input:
3
2
10
20
Sample Output:
1
8
22
My code is as follows:
/* #BEGIN_OF_SOURCE_CODE */
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char * argv[])
{
int sum = 0,
cases = 0,
i, j, buff;
scanf("%d", &cases); //Number of tests
int *n;
n = (int*) malloc(cases * sizeof(int)); //Defining array for numbers to be tested///////
for (i = 0; i < cases; i++) {
scanf("%d", &n[i]);
}
for (i = 0; i < cases; i++ ) {
buff = n[i] / 2;
if (n[i] == 1) {
sum = -1;
}
if (!(n[i] & 1)) {
for (j = 2; j < buff; j++) {
if (n[i] % j == 0) {
sum += n[i] / j + j;
buff /= j;
}
}
}
else {
for (j = 3; j < buff; j += 2) {
if (n[i] % j == 0) {
if (n[i] / j == j) { sum += j; break; }
else sum += n[i] / j + j;
}
buff /= j;
}
}
printf("%d\n", ++sum);
sum = 0;
}
return 0;
}
/* #END_OF_SOURCE_CODE */
but it is not fast enough. Any suggestions?

I have updated the code below to terminate sooner. Running it for all integers from 1 to 500,000 takes under half a second on a MacBookPro6,1 (2.66 GHz Intel Core i7), compiled with Apple GCC 4.2.1 with -O3.
It uses the formula for σx(n) in the Properties section of the Wikipedia page for the divisor function. It could be made faster with a list of precalculated primes. (126 are needed to support inputs up to 500,000, and this reduces the time to less than a quarter of a second.) There are also some divisions that can be eliminated, at the expense of cluttering the code slightly.
// Return the least power of a that does not divide x.
static unsigned int LeastPower(unsigned int a, unsigned int x)
{
unsigned int b = a;
while (x % b == 0)
b *= a;
return b;
}
// Return the sum of the proper divisors of x.
static unsigned int SumDivisors(unsigned int x)
{
unsigned int t = x;
unsigned int result = 1;
// Handle two specially.
{
unsigned int p = LeastPower(2, t);
result *= p-1;
t /= p/2;
}
// Handle odd factors.
for (unsigned int i = 3; i*i <= t; i += 2)
{
unsigned int p = LeastPower(i, t);
result *= (p-1) / (i-1);
t /= p/i;
}
// At this point, t must be one or prime.
if (1 < t)
result *= 1+t;
return result - x;
}

You don't have to allocate space. Just do line by line.
For each line, there is an O( n ^ 1/2 ) algorithm.
#include <iostream>
using std::cout; using std::endl; using std::cin;
int main() {
int count, number;
cin >> count;
for (int i = 0; i < count; ++i) {
cin >> number;
int sum = 1;
for ( int j = 2; j * j <= number; ++j ) {
if ( number % j == 0 ) {
sum += j;
sum += number / j;
}
if ( j * j == number ) sum -= j; // recalculate twice
}
cout << sum << endl;
}
}
This is the runtime for 200,000 test case
real 0m55.420s
user 0m0.016s
sys 0m16.124s

I would start by NOT storing the numbers in an array at all. You don't need to - just read the value, process it, and output the result. The compiler may well not realize that n[i] is the same value throughout the loop, and that nothing else modifies it.
The logic doesn't seem very clear to me. And if (n[i] == 1) { sum = 1} else ... would make more sense than setting sum = -1.
You could perhaps also, keep a list of "common factors" (http://en.wikipedia.org/wiki/Memoization), so that you don't have to recalculate the same thing many times over. [If you know that somehing has the factor 24, then it also has 2, 3, 4, 6 and 8, for example.

I replied to a similar question on stackoverflow
There is a faster performing algorithm which is based on a formula for the sum of divisor using the decomposition in prime factors.
First you construct a primetable such that the last prime squared is smaller than the upper bound for your number. Then you apply the formula to each entry. If a number is written as
n = a1^p1 * a1^p2 *... *an^pn
the complexity of finding the sum for a given number n will be
p1+p2+...+pn = roughtly log(n)
which is better than the complexity O(sqrt(n)) of the first optimization which stop the loop early

Let's suppose you have a way to compute primes relatively quickly. This could be a one time upfront activity, bounded by the square root of the largest input value. In this case, you already know the bound of the largest input value (500000), so you can simply hard code a table of primes into the program.
static unsigned P[] = {
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
};
static int P_COUNT = sizeof(P)/sizeof(*P);
Now, from the primes, for each input value, you can:
Compute the prime factorization
Compute the product of the sums of the powers of each prime factor.
This will result in the sum of the divisors. Subtract the input value from the sum to obtain the sum of proper divisors. These two steps can be combined into a single loop.
This algorithm works because multiplying polynomials naturally results in sums of all combinations of the polynomial terms multiplied together. In the case where each polynomial term consists of powers of primes that divide the input, the combinations of the terms multiplied together make up the divisors. The algorithm is fast, and should be able to process 500000 numbers in the interval [1, 500000] in less than a second on a Core i3 or better processor.
The following function implements the method described above.
unsigned compute (unsigned n) {
unsigned sum = 1;
unsigned x = n;
for (int i = 0; i < P_COUNT; ++i) {
if (P[i] > x / P[i]) break; /* remaining primes won't divide x */
if (x % P[i] == 0) { /* P[i] is a divisor of n */
unsigned sub = P[i] + 1; /* add in power of P[i] */
x /= P[i]; /* reduce x by P[i] */
while (x % P[i] == 0) { /* while P[i] still divides x */
x /= P[i]; /* reduce x */
sub = sub * P[i] + 1; /* add by another power of P[i] */
}
sum *= sub; /* product of sums */
}
}
if (x > 1) sum *= x + 1; /* if x > 1, then x is prime */
return sum - n;
}

The complexity of this code in O(n * log(n)). But you can output the required answer with constant time.
int ans[500000 + 10], m = 500000;
int f(){
for(int i = 1; i <= m; i++){
for(int j = i + i; j <= m; j += i){
ans[j] += i;
}
}
}
Here ans is an array that contain sum of proper divisor from 2 to m.

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.

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

trouble with solving knapsack issue via dynamic programming in C

I need to solve the knapsack problem recursively, memoized and with dynamic programming. Currently I'm stuck at the dynamic programming method.
I adapted the code from what I found elsewhere on the internet. Currently the output is not correct.
The problem involves profit and mass. Each item has a profit and mass associated, there is a MAX_N (umber) of items available and a MAX_CAPACITY for mass. The aim is to have as much "profit" in the knapsack as possible.
Here is an example provided by the exercise:
Example: Given a knapsack of capacity 5, and items with mass[] = {2, 4, 3, 2}
and profit profit[] = {45, 40, 25, 15}, the best combination would be item 0 (with mass 2 and profit 45) and item 2 (with mass 3 and with profit 25) for a total profit of 70. No other combination with mass 5 or less has a greater profit.
Here is the complete code:
#include <stdio.h>
#include <stdlib.h>
#define MAX_N 10
#define MAX_CAPACITY 165
int m[MAX_N][MAX_CAPACITY];
int max(int x, int y) {
return x ^ ((x ^ y) & -(x < y));
}
int min(int x, int y) {
return y ^ ((x ^ y) & -(x < y));
}
int knapsackRecursive(int capacity, int mass[], int profit[], int n) {
if (n < 0)
return 0;
if (mass[n] > capacity)
return knapsackRecursive(capacity, mass, profit, n-1);
else
return max(knapsackRecursive(capacity, mass, profit, n-1), knapsackRecursive(capacity - mass[n], mass, profit, n-1) + profit[n]);
}
int knapsackMemoized(int capacity, int mass[], int profit[], int n) {
}
int knapsackDynamic(int capacity, int mass[], int profit[], int n) {
int i;
int j;
for (i = 0; i <= n; i++) {
for (j = 0; j <= capacity; j++) {
if (i == 0 || j == 0)
m[i][j] = 0;
else if (mass[i-1] <= j)
m[i][j] = max(profit[i-1] + m[i-1][j-mass[i-1]], m[i-1][j]);
else
m[i][j] = m[i-1][j];
}
}
return m[n][capacity];
}
void test() {
// test values
//int M1[MAX_N] = {2, 4, 3, 2};
//int P1[MAX_N] = {45, 40, 25, 10};
int M1[MAX_N] = {6, 3, 2, 4};
int P1[MAX_N] = {50, 60, 40, 20};
int M2[MAX_N] = {23, 31, 29, 44, 53, 38, 63, 85, 89, 82};
int P2[MAX_N] = {92, 57, 49, 68, 60, 43, 67, 84, 87, 72};
// a)
printf("Recursion: %d\n",knapsackRecursive(MAX_CAPACITY, M1, P1, MAX_N));
printf("Recursion: %d\n",knapsackRecursive(MAX_CAPACITY, M2, P2, MAX_N));
printf("\n");
// b)
printf("Memoization: %d\n",knapsackMemoized(MAX_CAPACITY, M1, P1, MAX_N));
printf("Memoization: %d\n",knapsackMemoized(MAX_CAPACITY, M2, P2, MAX_N));
printf("\n");
// c)
printf("Dynamic Programming: %d\n",knapsackDynamic(MAX_CAPACITY, M1, P1, MAX_N));
printf("Dynamic Programming: %d\n",knapsackDynamic(MAX_CAPACITY, M2, P2, MAX_N));
}
int main() {
test();
}
This is the output I currently get. The recursive method should be supplying the correct result, but the dynamic programming one currently doesn't output the same. Memoization is not done yet, hence it doesn't output correctly either.
Recursion: 170
Recursion: 309
Memoization: 2686680
Memoization: 2686600
Dynamic Programming: 0
Dynamic Programming: 270
Process returned 25 (0x19) execution time : 0.269 s
Press any key to continue.
It turns out that the code I used for writing the dynamic programming part was supposed to work with int m[MAX_N+1][MAX_CAPACITY+1]; instead of int m[MAX_N][MAX_CAPACITY];.
Changing that has gotten me to a working code, if not really the code I wanted.

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.

for loop C work weird?

I have a problem with for loop in C.
The purpose of the program is to find prime numbers in known quantity k.
Here is my program:
unsigned int i, k, j;
unsigned long int prime;
int _tmain(int argc, _TCHAR* argv[]) {
printf("How many prime numbers do you want to print out in order? "); scanf_s("%u", &k);
printf("%u fist prime numbers are: ", k);
i = 1;
prime = 2;
while (i <= k)
{
for (j = 2; j <= prime; j++)
{
if (prime % j == 0)
{
if (j == prime && prime != 2)
{
printf("%lu, ", prime);
i++;
}
prime++;
j = 2;
}
}
}
_getch();
return 0;
}
And when I run the program, it returns infinite sequence of numbers. But if I adds "else j++;" like this:
for (j = 2; j <= prime; j++)
{
if (prime % j == 0)
{
if (j == prime && prime != 2)
{
printf("%lu, ", prime);
i++;
}
prime++;
j = 2;
}
else j++;
}
Then the program will work out properly. I think this is kinda weird and can't explain why?
Thanks in advance (and sorry for my bad English).
As I mentioned in comments, the problem was caused by your having no "break" in the for-loop to cause it to return to the outer while loop when you detected a valid divisor.
This was compounded by your poor use of variable names confusing you - your original code appears to be confused about what "j" and "prime" are.
Here I've refactored your code to be cleaner and give a significant performance increase for large prime searches:
#include <stdio.h>
#define FALSE (0)
#define TRUE (!(FALSE))
int main()
{
int numPrimes = 0;
int candidate, divisor;
int isPrime;
printf("How many prime numbers do you want to print out in order? ");
scanf("%u", &numPrimes);
printf("\n%u first prime numbers are:\n", numPrimes);
if (numPrimes > 0) {
printf("2, ");
--numPrimes;
}
// we only need to test odd numbers.
for (candidate = 3; numPrimes > 0; candidate += 2) {
// N / (N/2) + 1 is always < 1, so we only have to test half the values.
// we also only need to test odd divisors
isPrime = TRUE;
for (divisor = 3; divisor <= candidate / 2; ++divisor) {
// it's not prime if testNumber divides in
if (candidate % divisor == 0) {
isPrime = FALSE;
break;
}
}
if (isPrime) {
printf("%lu, ", candidate);
--numPrimes;
}
}
printf("\n");
return 0;
}
Live demo here: http://ideone.com/yrUPBy
Which gladly tells me
How many prime numbers do you want to print out in order?
1000 first prime numbers are:
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,
...
7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841,
7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919,
Your loop has j <= prime as the end condition, meaning the last value of j will be equal to prime. In that case (prime % j == 0) will always be true.
When you add the extra j++ you're skipping half the values of j which accidentally skips past the problem. The program still isn't working correctly.
When the program prints the prime 3, the variables have the following values:
i = 1
j = 3
prime = 3
Then you increment i and prime, and set j = 2, so it's:
i = 2
j = 2
prime = 4
Now you return to the top of the loop, which does j++:
i = 2
j = 3
prime = 4
Since j <= prime, the loop continues. Since prime % j is not 0, it skips the body of that if, and returns to the top of the loop, which increments j again:
i =2
j = 4
prime = 4
This time prime % j == 0, so it prints prime, even though it's not actually a prime number.
This keeps happening for every value of prime.
When you add j++ to the else clause, it causes j to be incremented twice in the failing case. So it goes from 3 to 5, and never makes it to the case where j == prime and it prints the number. Then j <= prime fails, so the for loop terminates.

Resources