How to find loop invariant of Sieve of Eratosthenes Algorithm? - algorithm

Can anyone help me to make loop invarients of Eratosthenes Algorithm please?
Here is the peace of code:
algorithm Sieve of Eratosthenes is
input: an integer n > 1.
output: all prime numbers from 2 through n.
let A be an array of Boolean values, indexed by integers 2 to n,
initially all set to true.
for i = 2, 3, 4, ..., not exceeding √n do
if A[i] is true
for j = i2, i2+i, i2+2i, i2+3i, ..., not exceeding n do
A[j] := false
return all i such that A[i] is true.

After the ith iteration, A[x] = false for all x <= n where x is a multiple of any integer j such that 2 <= j <= i.

You can do as
vector<int> getPrimes(int n) {
vector<bool> A(n + 1, true);
for (int i = 2; i * i <= n; i++) {
for (int j = i * i; j <= n; j += i) {
A[j] = false;
}
}
vector<int> primes;
for (int i = 2; i <= n; i++) {
if (A[i]) {
primes.push_back(i);
}
}
return primes;
}

Related

Time complexity of this algorithm? How to analysis?

Time complexity of this algorithm? How to analysis?
int fun(int n)
{
int i = 0, j = 0, m = 0;
for (i = n; i > 0; i /= 2)
{
for (j = 0; j < i; j++)
{
m += 1;
}
}
return m;
}
Your running time is Sum_i (n/2^{i}), for i in {0 to log(n)}. n is the leading term, thus O(n). The sum will not exceed 2n.

Does rearranging the outerloop in Floyd-Warshall algorithm as most inner loop change the algorithm

The following code is for Floyd-Warshall algorithm
for (int k = 0; k < n; ++k) {
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}
}
}
I propose to rewrite the code as follows
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
for (int k = 0; k < n; ++k) {
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}
}
}
In the new code, I put the original outer loop into the most inner loop. I find that the new code is easy to understand solving all pair shortest path problem.
My question is: is the new code equivalent to the original code for Floyd-Warshall algorithm?
No, that will in general not work. At the very heart of the Floyd–Warshall algorithm is the idea to find shortest paths that go via a smaller subset of nodes: 1..k, and to then increase the size of this subset.
It is essential that pairs of nodes will have their distance adapted to the subset 1..k before increasing the size of that subset.
As an example, take the example graph used on Wikipedia:
Let's focus on the path that exists from node 3 to node 1, which has a least-weight path of 2 + -1 + 4 = 5.
Let's run the original algorithm and your variant to see if it identifies this distance:
Original (Correct) Algorithm
let d = [
[0, Infinity, -2, Infinity],
[4, 0, 3, Infinity],
[Infinity, Infinity, 0, 2],
[Infinity, -1, Infinity, 0]
];
let n = d.length;
for (let k = 0; k < n; ++k) {
for (let i = 0; i < n; ++i) {
for (let j = 0; j < n; ++j) {
d[i][j] = Math.min(d[i][j], d[i][k] + d[k][j]);
}
}
}
console.log("distance from 3 to 1 = ", d[2][0]); // 5 -- correct
Your Suggested Algorithm
let d = [
[0, Infinity, -2, Infinity],
[4, 0, 3, Infinity],
[Infinity, Infinity, 0, 2],
[Infinity, -1, Infinity, 0]
];
let n = d.length;
for (let i = 0; i < n; ++i) {
for (let j = 0; j < n; ++j) {
for (let k = 0; k < n; ++k) {
d[i][j] = Math.min(d[i][j], d[i][k] + d[k][j]);
}
}
}
console.log("distance from 3 to 1 = ", d[2][0]); // Infinity -- wrong
If you turn the outer loop into the inner loop you get matrix multiplication over the tropical semiring (i.e. the one with min as addition and sum as multiplication) instead of Floyd Warshall.
It will compute the lowest-weight path with up to or exactly two steps. You can exponentiate the matrix by repeated squaring to get the same result as Floyd Warshall of course (with complexity O(V^3 log(V)), and it'll handle negative weight cycles better

Dividing n numbers into two groups each having sum less than equals k

There are n numbers, ranging 1-100. n ranges in 1-1000.
Another number k. Its bounds are 1 <= k <= 10^6
How to check if its possible to divide the given n numbers in two sets such that the sum of both group numbers is <=k.
I am looking for a high level implementation approach or an algorithm which will return true if the division is possible.
A DP based solution with a complexity of O(n*sum)
for (int i = 0; i < n; i++) {
sum += a[i];
}
int[][] dp = new int[n + 1][sum + 1];
for (int i = 0; i <= n; i++) {
dp[i][0] = 1;
}
for (int i = 0; i < n; i++) {
for (int j = 0; j <= sum; j++) {
dp[i + 1][j] = dp[i][j];
if (a[i] <= j) {
dp[i + 1][j] |= dp[i][j - a[i]];
}
}
}
for (int i = sum / 2; i >= 0; i--) {
if (dp[n][i] == 1) {
int x = sum - i;
if (x > k || i > k) {
System.out.println("NO");
} else {
System.out.println("YES");
}
break;
}
}

Find a subsequence of length k whose sum is equal to given sum

Given an array A and a sum, I want to find out if there exists a subsequence of length K such that the sum of all elements in the subsequence equals the given sum.
Code:
for i in(1,N):
for len in (i-1,0):
for sum in (0,Sum of all element)
Possible[len+1][sum] |= Possible[len][sum-A[i]]
Time complexity O(N^2.Sum). Is there any way to improve the time complexity to O(N.Sum)
My function shifts a window of k adjacent array items across the array A and keeps the sum up-to-data until it matches of the search fails.
int getSubSequenceStart(int A[], size_t len, int sum, size_t k)
{
int sumK = 0;
assert(len > 0);
assert(k <= len);
// compute sum for first k items
for (int i = 0; i < k; i++)
{
sumK += A[i];
}
// shift k-window upto end of A
for (int j = k; j < len; j++)
{
if (sumK == sum)
{
return j - k;
}
sumK += A[j] - A[j - k];
}
return -1;
}
Complexity is linear with the length of array A.
Update for the non-contiguous general subarray case:
To find a possibly non-contiguous subarray, you could transform your problem into a subset sum problem by subtracting sum/k from every element of A and looking for a subset with sum zero. The complexity of the subset sum problem is known to be exponential. Therefore, you cannot hope for a linear algorithm, unless your array A has special properties.
Edit:
This could actually be solved without the queue in linear time (negative numbers allowed).
C# code:
bool SubsequenceExists(int[] a, int k, int sum)
{
int currentSum = 0;
if (a.Length < k) return false;
for (int i = 0; i < a.Length; i++)
{
if (i < k)
{
currentSum += a[i];
continue;
}
if (currentSum == sum) return true;
currentSum += a[i] - a[i-k];
}
return false;
}
Original answer:
Assuming you can use a queue of length K something like that should do the job in linear time.
C# code:
bool SubsequenceExists(int[] a, int k, int sum)
{
int currentSum = 0;
var queue = new Queue<int>();
for (int i = 0; i < a.Length; i++)
{
if (i < k)
{
queue.Enqueue(a[i]);
currentSum += a[i];
continue;
}
if (currentSum == sum) return true;
currentSum -= queue.Dequeue();
queue.Enqueue(a[i]);
currentSum += a[i];
}
return false;
}
The logic behind that is pretty much straightforward:
We populate a queue with first K elements while also storing its sum somewhere.
If the resulting sum is not equal to sum then we dequeue an element from the queue and add the next one from A (while updating the sum).
We repeat step 2 until we either reach the end of sequence or find the matching subsequence.
Ta-daa!
Let is_subset_sum(int set[], int n, int sum) be the function to find whether there is a subset of set[] with sum equal to sum. n is the number of elements in set[].
The is_subset_sum problem can be divided into two subproblems
Include the last element, recur for n = n-1, sum = sum – set[n-1]
Exclude the last element, recur for n = n-1.
If any of the above subproblems return true, then return true.
Following is the recursive formula for is_subset_sum() problem.
is_subset_sum(set, n, sum) = is_subset_sum(set, n-1, sum) || is_subset_sum(set, n-1, sum-set[n-1])
Base Cases:
is_subset_sum(set, n, sum) = false, if sum > 0 and n == 0
is_subset_sum(set, n, sum) = true, if sum == 0
We can solve the problem in Pseudo-polynomial time using Dynamic programming. We create a boolean 2D table subset[][] and fill it in a bottom-up manner. The value of subset[i][j] will be true if there is a subset of set[0..j-1] with sum equal to i., otherwise false. Finally, we return subset[sum][n]
The time complexity of the solution is O(sum*n).
Implementation in C
// A Dynamic Programming solution for subset sum problem
#include <stdio.h>
// Returns true if there is a subset of set[] with sun equal to given sum
bool is_subset_sum(int set[], int n, int sum) {
// The value of subset[i][j] will be true if there is a
// subset of set[0..j-1] with sum equal to i
bool subset[sum+1][n+1];
// If sum is 0, then answer is true
for (int i = 0; i <= n; i++)
subset[0][i] = true;
// If sum is not 0 and set is empty, then answer is false
for (int i = 1; i <= sum; i++)
subset[i][0] = false;
// Fill the subset table in botton up manner
for (int i = 1; i <= sum; i++) {
for (int j = 1; j <= n; j++) {
subset[i][j] = subset[i][j-1];
if (i >= set[j-1])
subset[i][j] = subset[i][j] || subset[i - set[j-1]][j-1];
}
}
/* // uncomment this code to print table
for (int i = 0; i <= sum; i++) {
for (int j = 0; j <= n; j++)
printf ("%4d", subset[i][j]);
printf("\n");
} */
return subset[sum][n];
}
// Driver program to test above function
int main() {
int set[] = {3, 34, 4, 12, 5, 2};
int sum = 9;
int n = sizeof(set)/sizeof(set[0]);
if (is_subset_sum(set, n, sum) == true)
printf("Found a subset with given sum");
else
printf("No subset with given sum");
return 0;
}

Maximum Countiguous Negative Sum or Mnimum positive subsequence sum problem

We all heard of bentley's beautiful proramming pearls problem
which solves maximum subsequence sum:
maxsofar = 0;
maxcur = 0;
for (i = 0; i < n; i++) {
maxcur = max(A[i] + maxcur, 0);
maxsofar = max(maxsofar, maxcur);
}
What if we add an additional condition maximum subsequence that is lesser M?
This should do this. Am I wright?
int maxsofar = 0;
for (int i = 0; i < n - 1; i++) {
int maxcur = 0;
for (int j = i; j < n; j++) {
maxcur = max(A[j] + maxcur, 0);
maxsofar = maxcur < M ? max(maxsofar, maxcur) : maxsofar;
}
}
Unfortunately this is O(n^2). You may speed it up a little bit by breaking the inner loop when maxcur >=M, but still n^2 remains.
This can be solved using dynamic programming albeit only in pseudo-polynomial time.
Define
m(i,s) := maximum sum less than s obtainable using only the first i elements
Then you can calculate max(n,M) using the following recurrence relation
m(i,s) = max(m(i-1,s), m(i-1,s-A[i]]+A[i]))
This solution is similar to the solution to the knapsack problem.
If all A[i] > 0, you can do this in O(n lg n): precompute partial sums S[i], then binary search S for S[i] + M. For instance:
def binary_search(L, x):
def _binary_search(lo, hi):
if lo >= hi: return lo
mid = lo + (hi-lo)/2
if x < L[mid]:
return _binary_search(lo, mid)
return _binary_search(mid+1, hi)
return _binary_search(0, len(L))
A = [1, 2, 3, 2, 1]
M = 4
S = [A[0]]
for a in A[1:]:
S.append(S[-1] + a)
maxsum = 0
for i, s in enumerate(S):
j = binary_search(S, s + M)
if j == len(S):
break
sum = S[j-1] - S[i]
maxsum = max(sum, maxsum)
print maxsum
EDIT: as atuls correctly points out, the binary search is overkill; since S is increasing, we can just keep track of j each iteration and advance from there.
Solveable in O(n log(n)). Using a binary search tree (balanced) to search for smallest value larger than sum-M, and then update min, and insert sum, by going from left to right. Where sum is the partial sum so far.
best = -infinity;
sum = 0;
tree.insert(0);
for(i = 0; i < n; i++) {
sum = sum + A[i];
int diff = sum - tree.find_smallest_value_larger_than(sum - M);
if (diff > best) {
best = diff;
}
tree.insert(sum);
}
print best

Resources