Shortest path queries in a graph - java

We are given a static graph of N nodes, where we have edges as given below:
1. node-1 to node-i (for all 2 <= i <= N) of weight N + 1.
2. node-x to node-y (for all 2 <= x,y <= N) of weight 1, if and only if x divides y OR y divides x.
We are given Q queries of type(u, v) and we need to find shortest path between nodes u and v.
Constraints :
T <= 10^5 // number of test cases
N <= 2 * 10^5 // number of nodes
Q <= 2 * 10^5 // number of queries
u,v <= N
Approach : Almost constant time - O(1).
private int gcd(int x, int y) {
if(x % y == 0) return y;
return gcd(y, x % y);
}
private int lcm(int x, int y) {
return (x * y) / gcd(x, y);
}
private int[] shortest_path(int N, int Q, int[][] queries) {
int[] result = new int[Q];
int[] smallestDivisor = new int[N + 1];
for(int i = 2; i <= N; i++) {
if(smallestDivisor[i] == 0) {
int f = 1;
while(i * f <= N) {
if(smallestDivisor[i * f] == 0)
smallestDivisor[i*f] = i;
f += 1;
}
}
}
for(int i = 0; i < Q; i++) {
int u = queries[i][0];
int v = queries[i][1];
int LCM = lcm(u, v);
int GCD = gcd(u, v);
int smallestDivisorOfU = smallestDivisor[u];
int smallestDivisorOfV = smallestDivisor[v];
if(u == v)
result[i] = 0; // if nodes are same
else if(u == 1 || v == 1)
result[i] = N + 1; // if any of the node is '1'
else if(u % v == 0 || v % u == 0)
result[i] = 1; // if nodes are divisible
else if(GCD != 1 || LCM <= N)
result[i] = 2; // if gcd != 1 || lcm exists thus we can go as: 'x' --> gcd(x, y)/lcm(x,y) --> 'y' : 2 distance
else if(Math.min(smallestDivisorOfU * v, smallestDivisorOfV * u) <= N)
result[i] = 3;
else
result[i] = 2 * (N + 1); // we have to go via '1' node
}
return result;
}
Will this approach work for every test case?

Add GCD claculation before LCM to provide path A => GCD(A,B) => B (done)
When LCM checking fails, make factorization of values. If they are prime, move through "1" node. Otherwise check
if (min(SmallestDivisorOfA * B , SmallestDivisorOfB * A) <= N)
result[i] = 3;
Example: 7=>14=>2=>6

Related

How to find divisor of a number that is closest to its square root?

I've been trying to make a program that gives me a divisor of a number n that is closest to its square root.
I've tried to accomplish this by using this program:
public static int closestDivisor(int n) {
for (int i = n/ 2; i >= 2; i--) {
if (n % i == 0) {
return i;
}
}
return 1;
}
However, when I run this:
System.out.println(closestDivisor(42));
I get 21 when expecting either 6 or 7 because those are the closest divisors of 42.
if (i < 4) return 1;
int divisor = 1;
for (int i = 2; i < n; i++) {
if (i * i == n) return i;
if (i * i < n && n % i == 0) divisor = i;
if (i * i > n) return divisor;
}
return -1; // never executed, unreachable
This code should return the largest number which evenly divides n and which is less than or equal to the square root of n.
You can then look at this number, let's call it answer, and n/answer, and one of those is guaranteed to be the factor of n closest to the square root of n. To see which is which, we can compare n - answer*answer and (n/answer * n/answer) - n, and see which is smaller; if the first difference is smaller then answer is closer to n, otherwise n/answer is closer to n.
Here is one way.
First, return -1 if the candidate is < 0 or 1 if < 4
If n is a perfect square, return the square root.
Now inside the loop, Start from the square root and work outwards checking both sides of the square root for divisibility.
The default divisor is initialized to -1.
As the condition is evaluated either i divides n and i is returned via divisor
Otherwise k divides n and k is returned via divisor.
public static int closestDivisor(int n) {
if (n < 4) {
return n < 0 ? -1 : 1;
}
int v = (int)Math.sqrt(n);
int divisor = v;
if (v * v == n) {
return v;
}
for (int i = (int) v, k = i; i >= 1; i--, k++) {
if ( n % (divisor = i) == 0
|| (n % (divisor = k) == 0)) {
break;
}
}
return divisor;
}
public static int closestDivisor(int n) {
int closest = Integer.MAX_VALUE;
int closestDivisor = 1;
for (int i = 2; i <= Math.sqrt(n); i++) {
if (n % i == 0) {
if (Math.abs(i - n/i) < closest) {
closest = Math.abs(i - n/i);
closestDivisor = i;
}
}
}
return closestDivisor;

Problem when converting 'Fermat's primality test' from a Java to Python

I took the following program from here,
import java.io.*;
import java.math.*;
class GFG {
/* Iterative Function to calculate
// (a^n)%p in O(logy) */
static int power(int a,int n, int p)
{
// Initialize result
int res = 1;
// Update 'a' if 'a' >= p
a = a % p;
while (n > 0)
{
// If n is odd, multiply 'a' with result
if ((n & 1) == 1)
res = (res * a) % p;
// n must be even now
n = n >> 1; // n = n/2
a = (a * a) % p;
}
return res;
}
// If n is prime, then always returns true,
// If n is composite than returns false with
// high probability Higher value of k increases
// probability of correct result.
static boolean isPrime(int n, int k)
{
// Corner cases
if (n <= 1 || n == 4) return false;
if (n <= 3) return true;
// Try k times
while (k > 0)
{
// Pick a random number in [2..n-2]
// Above corner cases make sure that n > 4
int a = 2 + (int)(Math.random() % (n - 4));
// Fermat's little theorem
if (power(a, n - 1, n) != 1)
return false;
k--;
}
return true;
}
// Driver Program
public static void main(String args[])
{
int k = 3;
if(isPrime(11, k))
System.out.println(" true");
else
System.out.println(" false");
if(isPrime(15, k))
System.out.println(" true");
else
System.out.println(" false");
}
}
and converted into a Python program:
#############################
# random number generation
#############################
m = 4294967296
a = 1664525
c = 1013904223
seed = 1
def NextInt():
global seed
seed = (((a * seed + c) % m))
return seed
def NextInt2(min, max):
temp = NextInt()
ddd = temp / m
return int((max - min) * ddd + min)
def NextDouble():
temp = NextInt()
return temp / m
def NextDouble2(min, max):
temp = NextInt()
fraction = temp / m
return (max - min) * fraction + min
#######################################
# Fermet's method of primality test
#######################################
def Power(a, n, p):
res = 1;
a = a % p;
while (n > 0):
if ((n and 1) == 1):
res = (res * a) % p;
n = n / 2;
a = (a * a) % p;
return res;
def IsPrime(n, k):
if (n <= 1 or n == 4):
return False;
if (n <= 3):
return True;
while (k > 0):
a = 2 + NextInt() % (n - 4);
if (Power(a, n - 1, n) != 1):
return False;
k = k-1;
return True;
#####################
# Main Program
#####################
k = 3;
if(IsPrime(11, k)):
print(" true");
else:
print(" false");
if(IsPrime(15, k)):
print(" true");
else:
print(" false");
This Python program is always returning False.
Why?

How to encode a number using its prime factors in java using arrays?

I have this question I am trying to solve
I wrote this code
public static int[] encodeNumber(int n) {
int count = 0, base = n, mul = 1;
for (int i = 2; i < n; i++) {
if(n % i == 0 && isPrime(i)) {
mul *= i;
count++;
if(mul == n) {
break;
}
n /= i;
}
}
System.out.println("count is " + count);
int[] x = new int[count];
int j = 0;
for (int i = 2; i < base; i++) {
if(n % i == 0 && isPrime(i)) {
mul *= i;
x[j] = i;
j++;
if(mul == n) break;
n /= i;
}
break;
}
return x;
}
public static boolean isPrime(int n) {
if(n < 2) return false;
for (int i = 2; i < n; i++) {
if(n % i == 0) return false;
}
return true;
}
I am trying to get the number of its prime factors in a count variable and create an array with the count and then populate the array with its prime factors in the second loop.
count is 3
[2, 0, 0]
with an input of 6936. The desired output is an array containing all its prime factors {2, 2, 2, 3, 17, 17}.
Your count is wrong, because you count multiple factors like 2 and 17 of 6936 only once.
I would recommend doing it similar to the following way, recursively:
(this code is untested)
void encodeNumberRecursive(int remainder, int factor, int currentIndex, Vector<Integer> results) {
if(remainder<2) {
return;
}
if(remainder % factor == 0) {
results.push(factor);
remainder /= factor;
currentIndex += 1;
encodeNumberRecursive(remainder , factor, currentIndex, results);
} else {
do {
factor += 1;
} while(factor<remainder && !isPrime(factor));
if(factor<=remainder) {
encodeNumberRecursive(remainder , factor, currentIndex, results);
}
}
}
Finally, call it with
Vector<Integer> results = new Vector<Integer>();
encodeNumberRecursive(n, 2, 0, results);
You can also do it without recursion, I just feel it is easier.
Well here is a piece of code I would start with. It is not finished yet and I did not test it, but that's the way you should go basically.
// First find the number of prime factors
int factorsCount = 0;
int originalN = n;
while (n > 1) {
int p = findLowestPrimeFactor(n);
n /= p;
factorsCount++;
}
// Now create the Array of the appropriate size
int[] factors = new int[factorsCount];
// Finally do the iteration from the first step again, but now filling the array.
n = originalN;
int k = 0;
while (n > 1) {
int p = findLowestPrimeFactor(n);
factors[k] = p;
k++;
n = n / p;
}
return factors;
Having found a factor (on increasing candidates), you can assume it is prime,
if you divide out the factor till the candidate no longer is a factor.
Your problem is not repeatedly dividing by the factor.
public static int[] encodeNumber(int n) {
if (n <= 1) {
return null;
}
List<Integer> factors = new ArrayList<>();
for (int i = 2; n != 1; i += 1 + (i&1)) {
while (n % i == 0) { // i is automatically prime, as lower primes done.
factors.add(i);
n /= i;
}
}
return factors.stream().mapToInt(Integer::intValue).toArray();
}
Without data structures, taking twice the time:
public static int[] encodeNumber(int n) {
if (n <= 1) {
return null;
}
// Count factors, not storing them:
int factorCount = 0;
int originalN = n;
for (int i = 2; n != 1; i += 1 + (i&1)) {
while (n % i == 0) {
++factorCount;
n /= i;
}
}
// Fill factors:
n = originalN;
int[] factors = new int[factorCount];
factorCount = 0;
for (int i = 2; n != 1; i += 1 + (i&1)) {
while (n % i == 0) {
factors[factorCount++] = i;
n /= i;
}
}
return factors;
}

Solving a using Segment Tree

You are given a sequence A of N (N <= 50000) integers between -10000 and 10000. On this sequence you have to apply M (M <= 50000) operations:
modify the i-th element in the sequence or for given x y print max{Ai + Ai+1 + .. + Aj | x<=i<=j<=y }.
Problem Link
I am using Segment Tree for this but i am not getting the correct output , please Help me where i have committed the mistake
CODE:
Making a Tree:
public static void maketree(int current , int a , int b ,int[] arr){
if(b<a) return;
if(b==a) {dp[current] = arr[a]; return ;}
maketree(2*current, a, (a+b)/2, arr);
maketree(2*current+1,1+ (a+b)/2, b, arr);
if(dp[2*current]>0 && dp[2*current+1]>0) dp[current] = dp[2*current] + dp[2*current+1];
else if(dp[2*current]>dp[2*current+1]) dp[current] = dp[2*current];
else dp[current] = dp[2*current+1];
}
Updating Function
public static void update(int current , int a , int b , int c , int value){
if(a>b || c<a || c>b) return ;
if(a==b){ dp[current] = value; return ; }
update(2*current, a, (a+b)/2, c, value);
update(2*current+1, (b+a)/2 +1, b, c, value);
if(dp[2*current]>0 && dp[2*current+1]>0) dp[current] = dp[2*current] + dp[2*current+1];
else if(dp[2*current]>dp[2*current+1]) dp[current] = dp[2*current];
else dp[current] = dp[2*current+1];
}
Query Function:
public static int query(int current , int a , int b , int i , int j){
int ans =0;
if(a>j || b<i || a>b) return Integer.MIN_VALUE;
if(a>=i && b<=j) return dp[current];
int x = query(2*current, a, (a+b)/2, i, j);
int y = query(2*current+1, (a+b)/2 +1, b, i, j);
if(x>0 && y>0) ans= x+y;
else if(x>y) ans = x;
else ans =y;
return ans;
}
I don;t know where i have made mistake please help , What will storage capacity required for dp array i.e. size of dp
when you are merging two nodes,then it may be like given below.execute any simple example so that you can feel it :)
void merge(node a , node b)
{
sum = a.sum + b.sum;
pre = max(a.pre , (a.sum + b.pre));
suf = max(b.suf , (b.sum + a.suf));
result = max(a.suf + b.pre,max(a.result , b.result));
}
it is quite overcomplicated imo...
int tree[1 << 17]; // 2 ^ 17 >= N * 2
int M = 1; //base of tree or sth i dont remember english name
int query(int L, int R){
int res = -10000; //minimum possible value in array
L += M - 1;
R += M - 1;
while(L <= R){
if(L % 2 == 1) res = max(res, tree[L++];
if(R % 2 == 0) res = max(res, tree[R++];
L /= 2;
R /= 2;
}
return res;
}
void update(int v, int value){
v += M - 1;
tree[v] = value;
while(v > 0){
v /= 2;
tree[v] = max(tree[v * 2], tree[v * 2 + 1]);
}
}
void make_tree(){
int n;
cin >> n;
while(M < n) M *= 2; // M is half of the size of tree
for(int i = 0;i < n;i++)
cin >> tree[i + M]; // just reading input to tree;
for(int i = M - 1;i > 0;i--) // first update for all nodes other than leafs
tree[i] = max(tree[i * 2], tree[i * 2 + 1]);
}

finding the sum of number dividsable by x using recursion

I want to find the sum of numbers that is divisible by x using recursive method
Ex if n= 10, x=3, the code should return sum of 3+6+9
Write a recursive method sumDivByX(n, x), which finds the sum of all
numbers from 0 to n that are divisible by x.
I asked my teacher about it and he told me "Firstly, total should be global. You should return 0 if n or x == 0. I only care if n is divisible by x. So I only add n to total (total+=n) if (n%x==0) otherwise do nothing. And do recursion sumDivByX(n-1,x) and return total as usual." I tried to correct it.
public static int sumDivByX(int n, int x) {
int total = 0;
if (n == 0 || x == 0) {
return -1;
}
if (n % x >= 1) {
return total = 0;
} else if (n % x == 0) {
return total += n;
}
return total + sumDivByX(n - 1, x);
}
When I run the program I get 0.
Eliminate the returns inside your second and third if statements
public static int sumDivByX(int n, int x) {
int total = 0;
if (n == 0 || x == 0) {
return 0;
}
if (n % x >= 1) {
total = 0;
} else if (n % x == 0) {
total += n;
}
return total + sumDivByX(n - 1, x);
}
For a cuter, more compact version
public static int sumDivByX(int n, int x) {
if (n == 0 || x == 0) {
return 0;
}
return (n % x == 0 ? n : 0) + sumDivByX(n - 1, x);
}
Note - depending on the semantics you intend, you might want to have separate checks for x<=0 (possibly and error?) and n==0 (base case).
Step through your code and you'll see that it never recurses when n ==10 and x==3, since (10 % 3 == 1)
When a method gets to a "return" statement it ends, in your case at the second if.
Your total is initialized by 0 everytime the method runs, so you should consider making it global.
Your method generates an exception if you try to use negative numbers as paramethers
Try this:
int total=0;
public static int subDivByX(int n, int X) {
if (n>0 && x>0) {
if (n%x==0){
total += n;
}
return sumDivByX(n-1,x);
}
else return -1;
}
This seems to work
private static int sumDivByX(int n,int x) {
if (n < x || x < 1 ) {
return 0;
}
int d = n/x;
return (x * d) + sumDivByX(n - x , x);
}
Recursion could cause a stackoverflow.

Categories