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

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.

Related

List all the natural numbers below 10 that are multiples of 3 or 5

List all the natural numbers below 10 that are multiples of 3 or 5. We get 3, 5, 6 and 9. The sum of multiples is 23. Find the sum of all the multiples of 3 or 5.
I tried in many ways by using if else and if statements with while loops and for loops in many expected ways. I am mentioning one below, but it shows CODE IS TERMINATED DUE TO TIMEOUT. How to reduce the code? I am unable to get better code to reduce the time.
int main()
{
int t,a,n,i,sum;
scanf("%d",&t);
for(a=0;a<t;a++)
{
sum=0;i=3;
scanf("%d",&n);
while(i<n)
{
if((i%3==0)||(i%5==0))
{
sum=sum+i;
}
i++;
}
printf("%d\n",sum);
}
}
Here's a hint:
let's look at the repeating intervals of numbers that are divisible by 3 and/or 5
N 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
3 X X X X X X X X X X
5 X X X X X X
For the range of numbers 1-15, we can see the factors divisible by 3 or 5 are the following:
3, 5, 6, 9, 10, 12, 15 - the sum of which is 60
For the range of numbers 16-30, we can see the factors divisible by 3 or 5 are the following:
18, 20, 21, 24, 25, 27, 30 - the sum of which is 165
Or more generally for any interval between (N-14)..N where N is a number divisible by 15, the factors are this:
N+N-3+N-6+N-9+N-12+N-5+N-10 == 7*N - 45
So we can update the inner loop of your code:
scanf("%d",&n);
while(i<n)
{
if((i%3==0)||(i%5==0))
{
sum=sum+i;
}
i++;
}
To be this:
scanf("%d",&n);
int maxvalue = n-1;
int maxvalue = (maxvalue/15) * 15; // normalize to a multiple of 15
while (maxvalue >= 15)
{
sum += 7*maxvalue - 45;
maxvalue = maxvalue - 15;
}
Then to include the residual values for the last segment, it's the same as you had it.
for (int j = maxvalue+1; j < n; j++)
{
if (j % 3 == 0) || (j % 5 == 0)
{
sum += j;
}
}

Count ones in a segment (binary)

There is a problem which i am working on it right now and it's as the following :
there are two numbers x1 and x2 and x2 > x1.
for example x1 = 5; and x2 = 10;
and I must find the sum of ones between x1 and x2 in binary representations.
5 = 101 => 2 ones
6 = 110 => 2 ones
7 = 111 => 3 ones
8 = 1000 => 1 one
9 = 1001 => 2 ones
10= 1010 => 2 ones
so the sum will be
sum = 2 + 2 + 3 + 1 + 2 + 2 = 12 ones;
so I have managed to make a code without even transfer the numbers to binary and wasting execution time.
I noticed that the numbers of ones in every 2^n with n >= 1 is 1
Ex : 2^1 => num of ones is 1
2^2 => 1 2^15 => 1
you can test it here if you want: https://www.rapidtables.com/convert/number/decimal-to-binary.html?x=191
and between each 2^n and 2^(n+1) there are Consecutive numbers as you will see in this example :
num number of ones
2^4 = 16 1
17 2
18 2
19 3
20 2
21 3
22 3
23 4
24 2
25 3
26 3
27 4
28 3
29 4
30 4
31 5
2^5 = 32 1
so I write a code that can find how many ones between 2^n and 2^(n+1)
int t; ////turns
int bin = 1; //// numbers of ones in the binary format ,,, and 1 for 2^5
int n1 = 32; //// 2^5 this is just for clarification
int n2 = 64; //// 2^6
int *keep = malloc(sizeof(int) * (n2 - n1); ///this is to keep numbers because
/// i'll need it later in my consecutive numbers
int i = 0;
int a = 0;
n1 = 33 //// I'll start from 33 cause "bin" of 32 is "1";
while (n1 < n2) /// try to understand it now by yourself
{
t = 0;
while (t <= 3)
{
if (t == 0 || t == 2)
bin = bin + 1;
else if (t == 1)
bin = bin;
else if (t == 3)
{
bin = keep[i];
i++;
}
keep[a] = bin;
a++;
t++;
}
n1++;
}
anyway as you see I am close to solve the problem but they give me huge numbers and I must find the ones between them, unfortunately I have tried a lot of methods to calculate the "sum" using this above code and I ended up with time execution problem.
Ex: 1, 1000000000 the numbers of ones is >>> 14846928141
so can you give me a little hint what to do next, thanks in advance.
I'm doing this for CodeWar challenge: https://www.codewars.com/kata/596d34df24a04ee1e3000a25/train/c
You can solve this problem by computing the number of bits in the range 1 to n and use a simple subtraction for any subrange:
#include <stdio.h>
#include <stdlib.h>
/* compute the number of bits set in all numbers between 0 and n excluded */
unsigned long long bitpop(unsigned long long n) {
unsigned long long count = 0, p = 1;
while (p < n) {
p += p;
/* half the numbers in complete slices of p values have the n-th bit set */
count += n / p * p / 2;
if (n % p >= p / 2) {
/* all the numbers above p / 2 in the last partial slice have it */
count += n % p - p / 2;
}
}
return count;
}
int main(int argc, char *argv[]) {
unsigned long long from = 1000, to = 2000;
if (argc > 1) {
to = from = strtoull(argv[1], NULL, 0);
if (argc > 2) {
to = strtoull(argv[1], NULL, 0);
}
}
printf("bitpop from %llu to %llu: %llu\n", from, to, bitpop(to + 1) - bitpop(from));
return 0;
}
Here is a proposal for a speedup:
Find smallest y1 such that y1 >= x1 and that y1 is a power of 2
Find largest y2 such that y2 <= x2 and that y2 is a power of 2
Find p1 and p2 such that 2^p1=y1 and 2^p2=y2
Calculate the amount of 1:s between y1 and y2
Deal with x1 to y1 and y2 to x2 separately
Sum the results from 4 and 5
Let's focus on step 4. Let f(n) be the sum of ones up to (2^n)-1. We can quickly realize that f(n) = 2*f(n-1) + 2^(n-1) and that f(1)=1. This can be even further refined so that you don't have to deal with recursive calls, but I highly doubt it will be of any importance. Anyway, f(n) = n*2^(n-1)
To get the result between y1 and y2, just use f(p2)-f(p1)
For step 5, you can likely use a modified version of step 4.
EDIT:
Maybe I was to quick to say "quickly realize". Here is a way to understand it. The amounts of ones up to 2¹-1 is easy to see. The only two binary numbers below 2¹ are 0 and 1. To get the number of ones up to 2² we take the numbers below 2¹ and make a column:
0
1
Clone it:
0
1
0
1
And put 0:s before the first half and 1:s before the second half:
00
01
10
11
To get 2³ we do the same. Clone it:
00
01
10
11
00
01
10
11
And add 0 and 1:
000
001
010
011
100
101
110
111
Now it should be easy to see why f(n) = 2*f(n-1) + 2^(n-1). The cloning gives 2f(n-1) and adding the 0:s and 1:s gives 2^(n-1). If 2^(n-1) is hard to understand, remember that 2^(n-1)=(2^n)/2. In each step we have 2^n rows and half of them get an extra 1.
EDIT2:
When I looked at these columns, I got an idea for how to do step 5. Let's say that you want to find the amounts of 1:s from 10 to 15. Binary table for this would be:
10: 1010
11: 1011
12: 1100
13: 1101
14: 1110
15: 1111
Look at the interval 12-15. The last two digits in binary is a copy of the corresponding table for 0-3. That could be utilized, but I leave that to you.
EDIT 3:
This was a fun problem. I wrote some python code that does this. I get some problems with too many recursive calls, but that could be solved pretty easily, and it should not be too complicated to convert this to C:
def f(n):
return n*2**(n-1)
def numberOfOnes(x):
if(x==0):
return 0
p = floor(log(x,2))
a = f(p)
b = numberOfOnes(x-2**p)
c = x - 2**p +1
return a+b+c
I made an image so that you easier can understand what a, b and c does in the function numberOfOnes if we call it with numberOfOnes(12):
I have finally converted it to C. Of course I have used some code I found here on Stack overflow. I borrowed code for integer versions of log2 and pow, and made some small modifications.
This code is probably possible to optimize further, but it is not necessary. It is lighting fast, and I was not able to measure it's performance.
#include <stdio.h>
#include <math.h>
#include <assert.h>
#include <stdint.h>
#include <inttypes.h>
typedef uint64_t T;
// https://stackoverflow.com/a/11398748/6699433
const int tab64[64] = {
63, 0, 58, 1, 59, 47, 53, 2,
60, 39, 48, 27, 54, 33, 42, 3,
61, 51, 37, 40, 49, 18, 28, 20,
55, 30, 34, 11, 43, 14, 22, 4,
62, 57, 46, 52, 38, 26, 32, 41,
50, 36, 17, 19, 29, 10, 13, 21,
56, 45, 25, 31, 35, 16, 9, 12,
44, 24, 15, 8, 23, 7, 6, 5};
T log2_64 (T value) {
value |= value >> 1;
value |= value >> 2;
value |= value >> 4;
value |= value >> 8;
value |= value >> 16;
value |= value >> 32;
return tab64[((T)((value - (value >> 1))*0x07EDD5E59A4E28C2)) >> 58];
}
// https://stackoverflow.com/a/101613/6699433
T ipow(T base, T exp) {
T result = 1;
for (;;) {
if (exp & 1) result *= base;
exp >>= 1;
if (!exp) break;
base *= base;
}
return result;
}
T f(T n) { return ipow(2,n-1)*n; }
T numberOfOnes(T x) {
if(x==0) return 0;
T p = floor(log2(x));
T a = f(p);
T e = ipow(2,p);
T b = numberOfOnes(x-e);
T c = x - e + 1;
return a+b+c;
}
void test(T u, T v) {
assert(numberOfOnes(u) == v);
}
int main() {
// Sanity checks
test(0,0);
test(1,1);
test(2,2);
test(3,4);
test(4,5);
test(5,7);
test(6,9);
// Test case provided in question
test(1000000000,14846928141);
}
int x1 = 5;
int x2 = 10;
int i=0;
int looper = 0;
unsigned long long ones_count = 0;
for(i=x1; i<=x2; i++){
looper = i;
while(looper){
if(looper & 0x01){
ones_count++;
}
looper >>= 1;
}
}
printf("ones_count is %llu\n", ones_count);
return 0;
OUTPUT: ones_count is 12
Here is a way to count every single bit for every value in between the two values. The shift/mask will be faster than your arithmetic operators most likely, but will still probably time out. You need a clever algorithm like the other answer suggests i think, but heres the stupid brute force way :)
This was my solution to the problem:
** = exponentiation
/ = whole number division
Consider the numbers from 1 to 16:
00001
00010
00011
00100
00101
00110
00111
01000
01001
01010
01011
01100
01101
01110
01111
10000
If you pay attention to each column, you'll notice a pattern. The bit at column index i (0,1,2 ...) from the right runs through a cycle of length 2**(i+1), that is every 2**(i+1) rows, the pattern in column i repeats itself. Notice also that the first cycle starts at the first occurrence of a 1 in a given column. The number of ones in a pattern is half of the patterns length.
Example:
i pattern
0 10
1 1100
2 11110000
3 1111111100000000
...
So, given the task of summing all ones up to n, we have to keep track of how many times each pattern repeats itself and also if a pattern fails to complete itself.
Solution:
Let x be the biggest exponent of a binary number n and let s be the sum of all ones up to n. Then, for i = (0, 1, 2, ... , x) add (n / 2**(i+1)*(2**i) to s. If the remainder is bigger than 2**i, add 2**i to s, else add the remainder. Then subtract 2**i from n and repeat the process.
Example:
n = 7 -> x = 2
(7 / 2**1)*(2**0) = 3
7 % 2**1 = 1 !> 2**0
s = 1 + 3 (4)
n = n - 2**0 (6)
(6 / 2**2)*(2**1) = 2
6 % 2**2 = 2 !> 2**1
s = s + 2 + 2 (8)
n = n - 2**1 (4)
(4 / 2**3)*(2**2) = 0
4 % 2**3 = 4 !> 2**2
s = s + 4 (12)
n = n - 2**2 (0)
s = 12
Maybe not the best explanation or the most beautiful solution, but it works fine.
In python:
def cnt_bin(n):
bits = n.bit_length()
s = 0
for i in range(bits):
s += (n // 2**(i+1))*2**i
if n % 2**(i+1) > 2**i:
s += 2**i
else:
s += (n % 2**(i+1))
n -= 2**i
return s
Then, for a range [a, b] you just compute cnt_bin(b) - cnt_bin(a-1)

how to use recursion to formulate using simple array

I am a beginner in coding .I want to solve the following problem using simple recursion and array. But I can't visualize it. I came up with solution using link list .Following are problem and my way of solving
Given n rows of integers, such that the ith row (1 <= i <= n)
contains i integers. Using the following set of path rules, find the
path having the maximum weight.
Path traversal rules:
A valid path sequence would be top-down i.e. begins with the integer in the first row, and traverses all rows selecting only one
integer in each row.
From any jth integer in the ith row i.e. row[i][j], traversal can happen either downward (i.e. to row[i+1][j]) or diagonally downward
to the right (i.e. to row[i+1][j+1]).
The weight of a Path is the sum of values of integers in the Path
sequence.
Example:
No. of Rows: 5
4
2 9
15 1 3
16 92 41 44
8 142 6 4 8
Expected Output: 4, 2, 15, 92, 142 (Max weight is 255)
Sol.c
#include<stdio.h>
#include<stdlib.h>
int n,**ar;
struct n
{
int i,j;
int w;
struct n *ptr;
};
struct n* maxweight(int i,int j,struct n* x)
{
struct n* tmp=malloc(sizeof(struct n)),*t1,*t2;
tmp->i=i;
tmp->j=j;
tmp->ptr=x;
tmp->w=ar[i][j];
if(x)tmp->w+=x->w;
if(i==n-1)return tmp;
t1=maxweight(i+1,j,tmp);
t2=maxweight(i+1,j+1,tmp);
if(t1->w>t2->w)return t1;
return t2;
}
int main()
{
int i,j;
struct n * s;
printf("Enter the value of n\n");
scanf("%d",&n);
ar=malloc(n*sizeof(int*));
for(i=0;i<n;i++)
{
ar[i]=malloc((i+1)*sizeof(int));
for(j=0;j<=i;j++)scanf("%d",&ar[i][j]);
}
s=maxweight(0,0,NULL);
printf("MAX WEIGHT is :%d\nPATH: ",s->w);
while(s)
{
printf("%d ",ar[s->i][s->j]);
s=s->ptr;
}
printf("\n");
return 0;
}
How do I solve this using recursion simply without link-list using n x n matrix ? Is dynamic programming is applicable to this problem.
Focus on calculating the weight of the path that lies ahead of you; don't look back.
Start by solving a trivial edge case. Suppose you made it to the bottom row. Then there is nothing more to follow; the remaining path has weight zero.
In code:
int getWeight(int i, int j)
{
int remaining = 0;
In any other row, you have to make a choice. Should you go left or right? Since there is no way of knowing at this point which one is best, you just have to try both directions:
if (i < lastRow)
{
int weightLeft = getWeight(i + 1, j);
int weightRight = getWeight(i + 1, j + 1);
Notice I recursively called my own function; with a blind faith in that function's capability to come up with the optimal weight for the remaining path!
Having tried both directions, pick whichever came up with the highest weight:
int best_j = weightLeft > weightRight ? j : j + 1;
Now we walk the chosen path one more time.
remaining = getWeight(i + 1, best_j);
}
This is not very efficient, but it helps to collect the individual steps of the optimal path. I will use a straightforward array pathColumns.
pathColumns[i] = j;
Finally, we need to sum the values.
return row[i][j] + remaining;
}
To set the whole thing in motion, just call the function, and pass it the top cell's coordinates. For practical reasons, I made all arrays base-0. So the top cell is row[0][0].
printf("Optimal weight: %d\n", getWeight(0, 0));
Putting it all together:
#include <stdio.h>
#define n 5
int pathColumns[n] = {0};
int row[n][n] =
{
{4},
{2, 9},
{15, 1, 3},
{16, 92, 41, 44},
{8, 142, 6, 4, 8}
};
int getWeight(int i, int j)
{
int remaining = 0;
if (i < n-1) /* with base-0, the last row is n-1 */
{
int weightLeft = getWeight(i + 1, j);
int weightRight = getWeight(i + 1, j + 1);
int best_j = weightLeft > weightRight ? j : j + 1;
remaining = getWeight(i + 1, best_j);
}
pathColumns[i] = j;
return row[i][j] + remaining;
}
int main()
{
int i;
printf("Optimal weight: %d\n", getWeight(0, 0));
for (i = 0; i < n; i++)
{
int j = pathColumns[i];
printf("(%d, %d) = %d\n", i+1, j+1, row[i][j]);
/* NOTE: +1 is a correction to bring the output back to base-1 */
}
return 0;
}
Output:
Optimal weight: 255
(1, 1) = 4
(2, 1) = 2
(3, 1) = 15
(4, 2) = 92
(5, 2) = 142
How it works
We want getWeight(0, 0) to return the heaviest path for this pyramid.
4 <---- (0, 0) is our starting point
/ \
2 9
/ \ / \
15 1 3
/ \ / \ / \
16 92 41 44
/ \ / \ / \ / \
8 142 6 4 8
The recursive algorithm makes two recursive calls.
getWeight(1, 0) must get the heaviest path for the sub-pyramid below and to the left of our starting point.
getWeight(1, 1) must get the heaviest path for the sub-pyramid below and to the right of our starting point.
The two sub-pyramids:
2 <--- (1, 0) 9 <--- (1, 1)
/ \ / \
15 1 1 3
/ \ / \ / \ / \
16 92 41 92 41 44
/ \ / \ / \ / \ / \ / \
8 142 6 4 142 6 4 8
Assuming getWeight(1, 0) and getWeight(1, 1) return the correct weights (251 and 244, respectively), all there is left to do is pick the highest one (251) and add the top value of the big pyramid to it (4). The result is 255.
What we did is reduce a problem (calculate the maximum weight for a pyramid of height 5) so that we are left with two smaller problems to solve (calculate the maximum weight for pyramids of height 4). In the same way, we can reduce the problem for height 4 to solving the same problem for height 3. For example, getWeight(1, 1) will make two recursive calls getWeight(2, 1) and getWeight(2, 2):
1 <--- (2, 1) 3 <--- (2, 2)
/ \ / \
92 41 41 44
/ \ / \ / \ / \
142 6 4 6 4 8
getWeight(1, 1) should return 244 = 9 + max(235, 55).
Continuing this way, we eventually end up with solving the problem for pyramids of height 1. These are the values at the base of the original pyramid (8, 142, 6, 4 and 8). Here the recursion ends; a pyramid of height 1 is nothing more than a single node. The value of that node is the weight of the (only) path through that pyramid.

Summation of all proper divisors

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.

Given a sorted array, output all triplets <a,b,c> such that a-b = c

Given a sorted array, output all triplets such that a-b = c.
The code I tried so far is as below; but there are following test cases-
-12 = -7 - 5
-12 = 3 - 15
-7 = -4 - 3
-7 = 3 - 10
-7 = 9 - 16
-4 = 5 - 9
3 = -4 - -7
5 = -7 - -12
5 = 15 - 10
10 = 3 - -7
10 = 15 - 5
15 = 3 - (-12)
16 = 9 - (-7)
while my program prints only-
-12 = -7 - 5
-7 = -4 - 3
-12 = 3 - 15
-7 = 3 - 10
-4 = 5 - 9
-7 = 9 - 16
5 = 15 - 10
means only the abs difference! Any suggestion ll be great help!
void binder(int*a, int n) {
int i;
for (i = 0; i < n; i++) {
int current = a[i];
int left = 0;
int right = n-1;
while (left < right) {
if ( left == i ) {
left++;
continue;
}
if (right == i) {
right--;
continue;
}
if (a[left] + a[right] < current) {
left++;
} else if (a[left] + a[right] > current) {
right--;
} else {
printf("\n %d = %d - %d",a[left],current, a[right]);
left++;
right--;
}
}
}
}
int main() {
int a[] = {-12, -7, -4, 0, 3, 5, 9, 10, 15, 16};
binder(a, 10);
return 0;
}
It seems as though the test case is also missing a triplet:
9 = 5 - (-4)
Try changing your printing from:
printf("\n %d = %d - %d",a[left],current, a[right]);
to:
printf("\n %d = %d - %d",a[left],current, a[right]);
printf("\n %d = %d - %d",a[right],current, a[left]);
This solution is O(n^3), but it should work.
void binder(int*a, int n)
{
for(int left = 0; left < n; left++)
{
for(int right = 0; right < n; right++)
{
for(int result = 0; result < n; result++)
{
if(left != right && left != result && result != right && a[left] - a[right] == a[result])
printf("\n %d = %d - %d", a[result], a[left], a[right]);
}
}
}
}
How about something like this:
HashTable table;
for b = 0 to n-1:
for c = 0 to n-1:
table[b + c] = <b, c>
end for
end for
for a = 0 to n-1:
if table[a] exists and (<b, c> in table[a] where b != a and c != a) then:
output <a, b, c>
end if
end for
So, if we consider "a=b+c", for each (b, c) pair of values, we place that in a hash table, associating it with the (b, c) pair [O(n^2)].
Then, we go through the array again and if a value appears in the hash table, and the associated pairs are for different indices, then we've found a new entry (rearranging the terms back into "a-b=c"). This step is O(n), resulting in a O(n^2) solution overall.
I think we can see this question as a variation on the "find pairs of values in an array that sum up to S, for a fixed S" problem.
If they are sorted, (and as Hanning pointed out, a-b=c is the same as a=b+c) you can start with the smallest b and c, and add them, and this should lead to the smallest a. Now while increasing b or c, a can only get bigger too, so you should have never to look back.
If you make a table of b's and c's and their sum (which should be one of the a's):
c\ b:-12 3 4 5 7 10 15 16
-12: -24, -19, -9, -7, -3, -2, 3, 4
-7: -9, -4, 6, 8, 12, 13, 18,
3: -8, -3, 7, 9, 13, 14, 19,
5: -7, -2, 8, 10, 14, 15,
9: -5, 0, 10, 12, 16,
10: -2, 3, 13, 15,
15: 3, 8, 18,
16: 4, 9, 19,
you see, that I omited the values on the lower right, because the previous value (from left) already exceeded the maximum a (15), so a higher value can't match.
Of course, for such a small number of equations, you waste much more time thinking about optimization, than you gain from omitting superfluous calculations. For much bigger sets of values, it might be useful, to optimize.
you have missed one more iteration/loop in your code. since you are using brute force strategy so analysis say that it will take O(n^3) space and you code's time complexity seems O(n^2).
here is the case which will help you to understand.
you check for :
a = b-c
and you skip the check for :
c = b-a

Resources