How to use only one time bfs to solve this algorithm? - algorithm
The problem is uva1599, Visit https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4474
The problem is roughly described as below:
The labyrinth consists of n rooms connected by m path. Each path is colored into some color ci. Find the ideal path from the room number 1 to the
room number n. The path is the ideal path if its color sequence is the lexicographically smallest among shortest paths.(2<=n<=100000, 1<=m<=200000, 1<=c<=10^9)
I could use bfs from the end room to get the shortest path for each room, and use bfs again to search from the beginning if there is multi paths with the same length of path and different colors.
How to solve this problem with only one bfs?
I try to start from the end room using bfs get the shortest path and color sequence for each room. The idael path is stored in the room 1's color sequence.
Is that right?
Thanks.
This is my code. The error is runtime error
import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
public class IdealPath {
//store the path between two rooms, if there is a path between room i and j, then graph[i][j] = 1
public static int [][]graph;
//store the color between two rooms
public static int [][]color;
//store the shortest path to the end room for each room
public static int []distance;
//store the ideal color sequence for each room
public static String []color_seq;
//use for bfs
public static Queue<Integer> queue = new LinkedBlockingQueue<Integer>();
/**
* Initialize parameters
* #param n
*/
public static void init(int n){
graph = new int[n][n];
color = new int[n][n];
distance = new int[n];
color_seq = new String[n];
queue.clear();
}
/**
* use bfs to find the ideal path
* #param n
*/
public static void bfs(int n){
//init the end room
distance[n-1] = 0;
color_seq[n-1] = "";
queue.add(n-1);
//loop until the queue is empty
while(!queue.isEmpty()){
int node = queue.poll();
for (int i = 0; i < n; i++) {
//there is a path
if (graph[node][i] == 1){
//the room is not visited or is visited by the last floor
if (distance[i] == 0 || distance[i] == distance[node] + 1) {
distance[i] = distance[node] + 1; //add the distance
String str = color[i][node] + " " + color_seq[node]; //generate the color sequence
if (color_seq[i] == null)
color_seq[i] = str.trim();
//choose the ideal color sequence for the room
else
color_seq[i] = compare(color_seq[i], str) ? str.trim() : color_seq[i].trim();
queue.add(i);
}
}
}
}
}
/**
* return true if str2 < str1
* #param str1
* #param str2
* #return
*/
public static boolean compare(String str1, String str2){
String []arr2 = str2.trim().split(" ");
String []arr1 = str1.trim().split(" ");
//assume the lengths of arr1 and arr2 are same
for (int i = 0; i < arr1.length; i++) {
if (arr2[i].compareTo(arr1[i]) < 0)
return true;
}
return false;
}
public static void main(String []args){
Scanner input = new Scanner(System.in);
while(input.hasNext()){
//input
int n = input.nextInt();
int m = input.nextInt();
init(n);
for (int i = 0; i < m; i++) {
int node1 = input.nextInt() - 1;
int node2 = input.nextInt() - 1;
//ignore the path to itself
if (node1 != node2) {
graph[node1][node2] = graph[node2][node1] = 1;
int c = input.nextInt();
//choose the smallest path if it has multi path
color[node1][node2] = color[node2][node1] = (color[node1][node2] == 0) ? c : Math.min(c, color[node1][node2]);
}
}
//use bfs to find the ideal path
bfs(n);
//output
//the ideal path is stored in the color_seq[0]
String res = color_seq[0].trim();
System.out.println((res.length() + 1) / 2);
System.out.println(res);
}
}
}
Related
Algorithm to check whether students can be allocated to classes as per their preferences
In a coding hackathon I got following problem : There are K classes each having certain capacity. There are N students and each has one or two class preference. We need to print "YES" if all the students can be allocated to a class or else "NO". For example : N = 4 K = 3 capacity = {2,1,1} preference = {"0","0,2","1","2"} There are 4 students and 3 classes and as per their preferences following classes can be allocated: Student Classes 0 0 1 0 2 1 3 2 So the answer for the above scenario will be "YES" What will be algorithm approach to solve the above problem? Update: I used Christian's explanation below to come up with following solution: import java.util.*; public class StudentAllocation{ public static void main(String args[]){ int N = 4; int K = 3; int capacity[] = {2,1,1}; String preference[] = {"0","0,2","1","2"}; System.out.println(canAllocate(N,K,capacity,preference)); } public static String canAllocate(int N,int K,int c[],String p[]){ //Creating nodes for each student and capacity*class //Also making one node for source and on node for sink HashMap<String,Integer> nm = new HashMap<String,Integer>(); int n = 1; for(int i = 0;i < N;i++){ nm.put("s"+i,n++); } for(int i = 0;i < c.length;i++){ for(int j = 0;j < c[i];j++){ nm.put("c"+i+j,n++); } } n = n+1; int[][] g = new int[n][n]; //connecting source to all student nodes for(int i = 1;i <= N;i++){ g[0][i] = 1; } //connecting all capacity*class nodes to sink for(int i = N+1;i < n-1;i++){ g[i][n-1] = 1; } //Connecting student node to all the capcity node of class of his preference for(int i = 0;i < p.length;i++){ String ps = p[i]; String pst[] = ps.split(","); for(int j = 0;j < pst.length;j++){ for(int k = 0;k < c[Integer.parseInt(pst[j])];k++){ g[nm.get("s"+i)][nm.get("c"+pst[j]+k)] = 1; g[nm.get("s"+i)][nm.get("c"+pst[j]+k)] = 1; } } } //Using Ford Fulkerson to callculate max flow // If max flow is equal to no of students then each student can be allocated to any class of his preference //Making residual graph int rg[][] = new int[n][n]; for(int i = 0;i < n;i++){ for(int j = 0;j < n;j++){ rg[i][j] = g[i][j]; } } int parent[] = new int[n]; int max_flow = 0; int count = 0; while(bfs(rg,0,n-1,parent)){ count++; int path_flow = Integer.MAX_VALUE; for(int i = n-1;i != 0;i = parent[i]){ path_flow = Math.min(path_flow,rg[parent[i]][i]); } max_flow = max_flow + path_flow; for(int i = n-1;i != 0;i = parent[i]){ rg[parent[i]][i] -= path_flow; rg[i][parent[i]] += path_flow; } } if(max_flow == N){ return "YES"; } return "NO"; } public static boolean bfs(int rg[][],int u, int v, int[] p){ ArrayDeque<Integer> q = new ArrayDeque<Integer>(); q.offer(u); int marked[] = new int[rg.length]; while(!q.isEmpty()){ u = q.poll(); marked[u] = 1; for(int i = 0;i < rg[u].length;i++){ if(marked[i] != 1 && rg[u][i] > 0){ p[i] = u; q.add(i); if(i == v){ return true; } } } } return false; } }
You can create a bipartite graph with student nodes on one side, and then on the other side create class*capacities nodes. Each node represent one spot in a class. An edge from a student to a class node represents that this student is willing to take this spot. Note that a student is willing to take any spot in a class it has a preference to. The problem then is to find a perfect matching in this graph. If such a matching exists it is a "YES", if not it is a "NO".
Here is a recursive algorithm. We consider the last student, try their first choice and check if the problem for the remaining n-1 students can be solved. If not, try the second choice (if any), and again, check the problem for the remaining students. Here is an implementation in PHP (you can test it here): <?php function isSolvable($choices1, $choices2, $capacities, $n) { if($n==0) return true; // No students left to allocate // First choice of student $n $c1 = $choices1[$n-1]; if($capacities[$c1]>0) { $capacities[$c1]--; if(isSolvable($choices1, $choices2, $capacities, $n-1)) return true; $capacities[$c1]++; } // Second choice of student $n $c2 = $choices2[$n-1]; if($c2>=0 && $capacities[$c2]>0) { $capacities[$c2]--; if(isSolvable($choices1, $choices2, $capacities, $n-1)) return true; } return false; } $choices1 = [0, 0, 1, 2]; $choices2 = [-1, 2, -1, -1]; $capacities = [2, 1, 1]; echo isSolvable($choices1, $choices2, $capacities, count($choices1)) ? 'YES' : 'NO'; ?>
Return a subset of integers that maximizes its (mean - median)
A set of integers is given as input. You have to return the subset of that set so that the mean - median is maximum for that subset. Example 1 Input {1,2,3,4} Output {1,2,4} Example 2 Input {1,2,2,3,3} Output {2,2,3}
package subsetMean_Median; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class MySolution { public static void main(String[] args) { int[] arr= {2,3,2,1,3}; // {1,3,2,4}; Arrays.sort(arr); int[] outp=meanMedian(arr); for(int e:outp) { System.out.print(e+"\t"); } } protected static int[] meanMedian(int[] arr) { double median=findMedian(arr); double mean=findMean(arr); double diff=median-mean; int MAXINDEX=0; int n=arr.length; double sets=(1<<n); System.out.println("sets:"+sets); for(int i=1;i<=sets;i++) { int[] subset=findSubset(i,arr); mean=findMean(subset); median=findMedian(subset); if(mean -median>diff) { diff=mean-median;MAXINDEX=i; } } System.out.println("mean: "+mean+"\tmedian: "+median+"\tdiff: "+diff); return findSubset(MAXINDEX,arr); } protected static int[] findSubset(int counter, int[] arr) { int n=arr.length; List<Integer> ls=new ArrayList<Integer>(); for(int j=0;j<n;j++) { if((counter & (1<<j))>0) { ls.add(arr[j]); } } int[] output= new int[ls.size()]; for(int j=0;j<ls.size();j++) { output[j]=ls.get(j); } return output; } protected static double findMean(int[] arr) { int n=arr.length; double sum=0; if(n==0) return 0; for(int i=0;i<n;i++) sum +=arr[i]; return (sum/n); } protected static double findMedian(int[] arr) { int n=arr.length; if(n%2==1) return arr[(n/2)]; else if(n>=2) return 0.5*(arr[((n-2)/2)]+arr[n/2]); else return 0; } }
For every possible median: lllllmrrrrr Sort both parts L and R, then start choosing in pair lr maximal elements from both parts and with addition of every next element recompute mean, store arrangement with the best difference. Then the same for minimal elements. There are about N possible medians, sorting takes O(N*lgN), on every iteration you need to compute up to N means, you can do it in O(N). So, overall complexity is O(N^3*LgN), but most likely you can avoid sorting on every iteration, instead sort whole array only once and update parts in O(1) on every iteration. With such an improvements it is O(N^2).
The most important thing in this problem is to find the Subset. import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class MeanMedian { public static void main(String[] args) { int[] arr = { 1, 2, 3 };// { 1, 2, 2, 3, 3 };// { 1, 2, 3, 4 }; returnMaxMeanMedian(arr); } private static void returnMaxMeanMedian(int[] arr) { double max = -999.9; List<Integer[]> subArr = subSet(arr); Integer[] maxArr = new Integer[1]; for (Integer[] sub : subArr) { double newMax = calcDiff(sub); if (max <= newMax) { max = newMax; maxArr = sub; } } System.out.println(Arrays.toString(maxArr)); } private static double calcDiff(Integer[] sub) { // calc. mean double sum = 0; for (int i = 0; i < sub.length; i++) { sum += sub[i]; } sum = sum / sub.length; // calc. median double median = 0; if (sub.length % 2 == 0) median = (double) (sub[(sub.length / 2) - 1] + sub[sub.length / 2]) / 2; else median = sub[sub.length / 2]; double diff = sum - median; return diff; } private static List<Integer[]> subSet(int[] arr) { List<Integer[]> subArr = new ArrayList<Integer[]>(); int n = arr.length; // Run a loop until 2^n // subsets one by one for (int i = 0; i < (1 << n); i++) { String subSet = ""; // Print current subset for (int j = 0; j < n; j++) if ((i & (1 << j)) > 0) subSet += arr[j] + " "; subArr.add(convertToInt(subSet.trim().split(" "))); } return subArr; } private static Integer[] convertToInt(String[] arr) { if (arr[0] == "") return new Integer[] { 0 }; Integer[] intArr = new Integer[arr.length]; for (int i = 0; i < arr.length; i++) { intArr[i] = Integer.parseInt(arr[i].trim()); } return intArr; } }
Sort the list in O(n log n). Deleting any element to the left of the median (center element or pair) has the same effect on the median, but affect the mean differently. Ditto for elements to the right. That means that if anything will improve (mean - median), one of these will improve it the most: the smallest element in the array the smallest element to the right of the median one of the element(s) that comprises the median I.e., for each possible new median, how can we achieve the largest mean? Repeatedly check these 3-4 for improving mean-median, deleting whatever improves the most. Each operation is O(1), as is recalculating the mean and median. You have to do this at most O(n) times. The running time is O(n log n) if the list is unsorted, otherwise O(n).
Is this question only for a positive sequence of numbers? If yes, there's this efficient piece of code I wrote: import java.util.Scanner; public class MeanMedian { public static void main(String[] args) { // TODO Auto-generated method stub Scanner sc = new Scanner(System.in); int i; int j; int k; int in_length; int mid_loc; int sum_arr; float median = 0.0f; float mean = 0.0f; float delta = 0.0f; float incremental_delta = 0.0f; float MEDIAN_FOR_MAX_DELTA = 0.0f; float MEAN_FOR_MAX_DELTA = 0.0f; float MAX_DELTA = -1.0f; int MAX_SEQ_LENGTH = 0; System.out.print("Enter the length of input: "); in_length = sc.nextInt(); int in_arr[]= new int [in_length+1]; int out_arr[] = new int [in_length+1]; //This is the maximum size of the output array. int MAX_DELTA_ARR[] = new int [in_length+1]; // STAGE-1: Accept the input sequence for (i = 1; i <= in_length; i++) { System.out.print("Enter the input #" + i + ": "); in_arr[i] = sc.nextInt(); } // STAGE-1 completed. // STAGE-2: Sort the array (Bubble sort in Ascending order) for (j = 1; j < in_length; j++) { for (i = in_length; i > j; i--) { if (in_arr[i-1] > in_arr[i]) { k = in_arr[i]; in_arr[i] = in_arr[i-1]; in_arr[i-1] = k; } } } // STAGE-2 completed. // STAGE-3: Compute Max Delta MAX_DELTA = -99999; //Store as large -ve number as float data type can hold. for (i = in_length; i > 2; i--) { // STAGE-3a: Optional - Clear the out_arr[] for (j = 1; j <= in_length; j++) { out_arr [j] = 0; } // STAGE-3a completed. // STAGE-3b: Determine the index of the median for the sequence of length i if (i % 2 == 1) { mid_loc = (i + 1)/2; } else { mid_loc = (i / 2) + 1; } // STAGE-3b completed. // STAGE-3c: Create the selection that gives the min median and max mean. // STAGE-3c1: Create left side of mid point. for (j = mid_loc; j > 0; j--) { out_arr[j] = in_arr[j]; } // STAGE-3c1 completed. // STAGE-3c2: Create right side of mid point. k = in_length; for (j = i; j > mid_loc; j--) { out_arr[j] = in_arr[k]; k = k - 1; } // STAGE-3c2 completed. // STAGE-3c3: Do the SHIFT TEST. //for (; k <= mid_loc + in_length - i; k++) { for (k = mid_loc + 1; k <= mid_loc + in_length - i; k++) { if (i % 2 == 1) { incremental_delta = ((float)in_arr[k] - (float)out_arr[1])/i - ((float)in_arr[k] - (float)out_arr[mid_loc]); } else { incremental_delta = ((float)in_arr[k] - (float)out_arr[1])/i - (((float)in_arr[k] - (float)out_arr[mid_loc]/2)); } if (incremental_delta >= 0 ) { //Insert this new element for(j = 1; j < mid_loc; j++) { out_arr[j] = out_arr[j+1]; } out_arr[mid_loc] = in_arr[k]; } } // STAGE-3c3 completed. // STAGE-3d: Find the median of the present sequence. if(i % 2 == 1) { median = out_arr[mid_loc]; } else { median = ((float)out_arr[mid_loc] + (float)out_arr[mid_loc - 1])/2; } // STAGE-3d completed. // STAGE-3e: Find the mean of the present sequence. sum_arr = 0; for(j=1; j <= i ; j++) { sum_arr = sum_arr + out_arr[j]; } mean = (float)sum_arr / i; // STAGE-3e completed. // STAGE-3f: Find the delta for the present sequence and compare with previous MAX_DELTA. Store the result. delta = mean - median; if(delta > MAX_DELTA) { MAX_DELTA = delta; MEAN_FOR_MAX_DELTA = mean; MEDIAN_FOR_MAX_DELTA = median; MAX_SEQ_LENGTH = i; for (j = 1; j <= MAX_SEQ_LENGTH; j++) { MAX_DELTA_ARR[j] = out_arr[j]; } } // STAGE-3f completed. } // STAGE-4: Print the result. System.out.println("--- RESULT ---"); System.out.print("The given input sequence is: "); System.out.print("{ "); for(i=1; i <= in_length; i++) { System.out.print(in_arr[i]); System.out.print(" "); } System.out.print("}"); System.out.println(""); System.out.print("The sequence with maximum difference between mean and median is: "); System.out.print("{ "); for(i=1; i <= MAX_SEQ_LENGTH; i++) { System.out.print(MAX_DELTA_ARR[i]); System.out.print(" "); } System.out.print("}"); System.out.println(""); System.out.println("The mean for this sequence is: " + MEAN_FOR_MAX_DELTA); System.out.println("The median for this sequence is: " + MEDIAN_FOR_MAX_DELTA); System.out.println("The maximum difference between mean and median for this sequence is: " + MAX_DELTA); } } This code has order O(n) (if we ignore the necessity to sort the input array). In case, -ve inputs are also expected - the only way out is by evaluating each subset. The downside to this approach is that the algorithm has exponential order: O(2^n). As a compromise you could use both types of algorithm in your code and switch between the two by evaluating the input sequence. By the way, where did you come across this question?
from itertools import combinations [Verfication of the code][1] # function to generate all subsets possible, there will be 2^n - 1 subsets(combinations) def subsets(arr): temp = [] for i in range(1, len(arr)+1): comb = combinations(arr, i) for j in comb: temp.append(j) return temp # function to calculate median def median(arr): mid = len(arr)//2 if(len(arr)%2==0): median = (arr[mid] + arr[mid-1])/2 else:` median = arr[mid] return median # function to calculate median def mean(arr): temp = 0 for i in arr: temp = temp + i return temp/len(arr) # function to solve given problem def meanMedian(arr): sets = subsets(arr) max_value = 0 for i in sets: mean_median = mean(i)-median(i) if(mean_median>max_value): max_value = mean_median needed_set = i return needed_set [1]: https://i.stack.imgur.com/Mx4pc.png
So I tried a little on the problem and here is a code that might help you. Its written in a way that should be easy to read, and if not, do let me know. Maybe you need to take array input from the user as I have taken a fixed array. That shouldn't be much of a problem I am sure. import java.util.ArrayList; import java.util.Arrays; import java.util.List; class MeanMinusMedian { private static float mean = 0; private static float median = 0; private static float meanMinusMedian = 0; private static List<Integer> meanMinusMedianList = null; private static void formMeanMinusMedianArr(int data[], int sumOfData) { findMean(data, sumOfData); findMedian(data); if ((mean - median) > meanMinusMedian) { meanMinusMedian = mean - median; meanMinusMedianList = new ArrayList<Integer>(); Arrays.stream(data) .forEach(e->meanMinusMedianList.add(e)); } } /** * #param data */ private static void findMedian(int[] data) { int dataLen = data.length; median = data.length % 2 == 0 ? ((float)data[dataLen / 2] + (float)data[dataLen / 2 - 1]) / 2 : data[dataLen / 2]; } /** * #param data * #param sumOfData */ private static void findMean(int[] data, int sumOfData) { mean = ((float)sumOfData /(float) data.length); } /** * * #param arr * #param data * #param start * #param end * #param index * #param runningVal */ private static void combinationUtil(int arr[], int data[], int start, int end, int index, int runningVal) { // Current combination is ready to be printed, print it if (index == runningVal) { formMeanMinusMedianArr(data, Arrays.stream(data) // Step 1 .sum()); return; } // replace index with all possible elements. The condition // "end-i+1 >= r-index" makes sure that including one element // at index will make a combination with remaining elements // at remaining positions for (int i = start; i <= end && end - i + 1 >= runningVal - index; i++) { data[index] = arr[i]; combinationUtil(arr, data, i + 1, end, index + 1, runningVal); } } /** * * #param arr * #param n * #param runningVal */ private static void printCombination(int arr[], int n, int runningVal) { int data[] = new int[runningVal]; // Print all combination using temporary array 'data[]' combinationUtil(arr, data, 0, n - 1, 0, runningVal); } public static void main(String[] args) { int arr[] = { 1, 2, 2, 3, 3 }; int runningVal = 1;//Running value int len = arr.length; for (int i = 1; i < arr.length; i++) { printCombination(arr, len, runningVal + i); } System.out.println(meanMinusMedianList); } }
Taking reference of answer of Bhaskar13 https://stackoverflow.com/a/59386801/3509609 , I solved it without using the bit shift operators, to add more readability. package array; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Map; public class MeanMinusMedianMax { public static void main(String[] args) { System.out.println(Arrays.toString(maxDiffrenceSubSet(4, new int[] { 4, 2, 3, 1 }))); System.out.println(Arrays.toString(maxDiffrenceSubSet(4, new int[] { 1, 2, 2, 3, 3 }))); } public static int[] maxDiffrenceSubSet(int n, int[] input2) { int totalSubsets = (int) Math.pow(2, n); Map<Integer, ArrayList<Integer>> subsetsMap = new HashMap<Integer, ArrayList<Integer>>(); Integer maxKey = null; double maxDiff = 0; for (int i = 0; i < totalSubsets; i++) { String binaryString = Integer.toBinaryString(i); while (binaryString.length() < 4) { binaryString = "0" + binaryString; } char[] currentPick = binaryString.toCharArray(); ArrayList<Integer> currentList = new ArrayList<Integer>(); for (int x = 0; x < currentPick.length; x++) { if ((currentPick[x]) == '1') { currentList.add(input2[x]); } } Collections.sort(currentList); subsetsMap.put(i, currentList); double mean = findMean(currentList); double median = findMedian(currentList); double currentDifference = mean - median; if (currentDifference > maxDiff) { maxDiff = currentDifference; maxKey = i; } } return subsetsMap.get(maxKey).stream().mapToInt(i -> i).toArray(); } static double findMean(ArrayList<Integer> arr) { int n = arr.size(); double sum = 0; if (n == 0) return 0; for (int i = 0; i < n; i++) sum += arr.get(i); return (sum / n); } static double findMedian(ArrayList<Integer> arr) { int n = arr.size(); if (n % 2 == 1) return arr.get((n / 2)); else if (n >= 2) return 0.5 * (arr.get(((n - 2) / 2)) + arr.get(n / 2)); else return 0; } }
class UserMainCode (object): def meanmedian(cls,ip1,ip2=[]): s = [] s = ip2 lst = [] final = [] op = [] max_val = 0 diff = 0 for i in range(1,ip1+1): n=i lst = list(itertools.combinations(s,n)) final = final +lst for i in range(len(final)): men = statistics.mean(final[i]) med = statistics.median(final[i]) diff = men - med if max_val < diff: op = final[i] max_val = diff return op
Dissociated press algorithm using ngram
I solve that kind of algorithm, and stuck how does algorithm works. Dissociated press algorithm is https://en.wikipedia.org/wiki/Dissociated_press N gram - https://en.wikipedia.org/wiki/N-gram can make possible random string in consecutive string, so It can be implemented. The dissociated press algorithm starts by printing a random n-gram. Then it takes the last n-1 words it has printed, and chooses a random n-gram that starts with these n-1 words. It prints the last word of this n-gram, and repeats. So every consecutive n words of the output text are an n-gram of the original text. In can sometimes happen that the original text contains no n-gram starting with the n-1 words just printed. In this case, the algorithm simply stops. actually I don't know. how It is terminated. ngram(1,2) ngram(2,3) ngram (3,4) ........ T T is any example for me? I can't understand its text.
Well, first you split the test into n-grams: The dissociated press algorithm starts by printing a random n-gram. becomes (for n = 4) the dissociated press algorithm dissociated press algorithm starts press algorithm starts by algorithm starts by printing starts by printing a by printing a random printing a random n-gram etc. Then, you start with any n-gram you like, and start adding words that would complete last n-1 words of the text built so far to a known n-gram. As a result, the text you create seems almost readable — the larger n is, the more readable text you'll have.
It is not an awfully complex algorithm. The given version runs quite well: public class Dissociator { // Required size of the overlap int overlapSize = 8; // Size of the fragment int fragmentSize = overlapSize; // The initial sequence to dissociate, characters or words (could also dissociate some other objects). ArrayList<String> initial; boolean space; boolean wordMode; Random r = new Random(System.currentTimeMillis()); // Dissociate the given string. public String dissociate(String in) { ArrayList<String> a; if (wordMode) a = wordBased(in); else a = charBased(in); ArrayList<String> out = dissociate(a); StringBuilder b = new StringBuilder(out.size()); for (String s : out) { b.append(s); if (wordMode) b.append(' '); } return b.toString(); } /** * Run dissociation algorithm * * #param input the initial sequence * #return the dissociated sequence. */ public ArrayList<String> dissociate(ArrayList<String> input) { initial = input; ArrayList<String> out = new ArrayList<String>(); while (out.size() < input.size()) { int size = r.nextInt(overlapSize); if (size == 0) size = 1; ArrayList<String> tail = getTailOf(out, size); // Find random sequence in the input that matches the tail int p = r.nextInt(input.size() - 1) + 1; // Avoid zero. int was = p - 1; // This variable allows to break dissociation if it is not possible to find // the acceptable continuation. boolean ok = false; if (tail.size() > 0) do { while (input.get(p).equals(tail.get(0)) && p != was) p = (p + 1) % input.size(); for (int j = 1; j < tail.size(); j++) if (j + p < input.size()) { if (!tail.get(j).equals(input.get(j + p))) { ok = false; break; } } ok = true; } while (!ok && p != was); for (int j = p; j < Math.min(p + fragmentSize, input.size()); j++) out.add(input.get(j)); } return out; } // Get the tail of the given size. private ArrayList<String> getTailOf(ArrayList<String> out, int size) { if (size >= out.size()) return out; else { ArrayList<String> r = new ArrayList<String>(size); for (int p = out.size() - size; p < out.size(); p++) { r.add(out.get(p)); } return r; } } private static ArrayList<String> charBased(String in) { ArrayList<String> is = new ArrayList<String>(); for (int i = 0; i < in.length(); i++) is.add(in.substring(i, i + 1)); return is; } private static ArrayList<String> wordBased(String in) { ArrayList<String> is = new ArrayList<String>(); StringTokenizer st = new StringTokenizer(in, " ,:()?!\"'"); while (st.hasMoreTokens()) is.add(st.nextToken()); return is; } public static void main(String[] args) throws Exception { String in; File f = new File(args[0]); BufferedReader r = new BufferedReader(new FileReader(f)); String sr; StringBuilder bb = new StringBuilder((int) f.length()); while ((sr = r.readLine()) != null) { bb.append(sr); bb.append(' '); } in = bb.toString(); Dissociator d = new Dissociator(); String b = d.dissociate(in); System.out.println(b); } }
Construct the largest possible rectangle out of line segments of given lengths
I recently participated in a competition where I was asked this question. Given an array with lengths what is the area of the biggest rectangle that can be made using ALL the lengths. The lengths can be added but not broken in between. Example: [ 4,2,4,4,6,8 ] given this array the best we can do is make a rectangle of sides 8 and 6 like this. giving an area of 8 * 6 = 48. I am a beginner and even after a long hard think about how to do it I am unable to get anywhere. I am not looking for a solution but any clue to nudge me in the right direction would be appreciated. TIA Edit: Somebody pointed out(comment deleted now) that its difficult to explain the solution with just hints and not posting some code. Kindly post code if necessary.
The problem is NP-Hard, thus the backtracking solution [or other exponential solution as suggested by #vhallac] will be your best shot, since there is not known [and if P!=NP, there is no existing] polynomial solution for this kind of problem. NP-Hardness proof: First, we know that a rectangle consists of 4 edges, that are equal in pairs [e1=e2,e3=e4]. We will show that if there is a polynomial algorithm A to this problem, we can also solve the Partition Problem, by the following algorithm: input: a group of numbers S=a1,a2,...,an output: true if and only if the numbers can be partitioned algorithm: sum <- a1 + a2 + .. + an lengths <- a1, a2 , ... , an , (sum*5), (sum*5) activate A with lengths. if A answered there is any rectangle [solution is not 0], answer True else answer False Correctness: (1) if there is a partition to S, let it be S1,S2, there is also a rectangle with edges: (sum*5),(sum*5),S1,S2, and the algorithm will yield True. (2) if the algorithm yields True, there is a rectangle available in lengths, since a1 + a2 + ... + an < sum*5, there are 2 edges with length sum*5, since the 2 other edges must be made using all remaining lengths [as the question specified], each other edge is actually of length (a1 + a2 + ... + an)/2, and thus there is a legal partition to the problem. Conclusion: There is a reduction PARTITION<=(p) this problem, and thus, this problem is NP-Hard EDIT: the backtracking solution is pretty simple, get all possible rectangles, and check each of them to see which is the best. backtracking solution: pseudo-code: getAllRectangles(S,e1,e2,e3,e4,sol): if S == {}: if legalRectangle(e1,e2,e3,e4): sol.add((e1,e2,e3,e4)) else: //S is not empty elem <- S[0] getAllRectangles(S-elem,e1+elem,e2,e3,e4,sol) getAllRectangles(S-elem,e1,e2+elem,e3,e4,sol) getAllRectangles(S-elem,e1,e2,e3+elem,e4,sol) getAllRectangles(S-elem,e1,e2,e3,e4+elem,sol) getRectangle(S): RECS <- new Set getAllRectangles(S,{},{},{},{},RECS) getBest(RECS) EDIT2: As discussed in the comments, this answer shows not only this is hard to find the BEST rectangle, it is also hard to find ANY rectangle, making this problem hard for heuristic solutions as well.
Here is one solution to the problem in Python. It is not optimized at all. I even check 2, 4 after I check 4,2, for example. But for showing how you can find a solution, I think it is good enough. def all_but(lst, pos): return lst[0:pos]+lst[pos+1:] def find_sets_with_len(segs, l): for i in range(0, len(segs)): val = segs[i] if (val == l): yield [val], all_but(segs, i) if (val < l): for soln, rest in find_sets_with_len(all_but(segs, i), l - val): yield [val]+soln, rest def find_rect(segs, l1, l2): for side1, rest1 in find_sets_with_len(segs, l1): for side2, rest2 in find_sets_with_len(rest1, l1): for side3, rest3 in find_sets_with_len(rest2, l2): return [side1, side2, side3, rest3] def make_rect(segs): tot_len = sum(segs) if (tot_len %2) == 0: opt_len=tot_len/4 for l in range(opt_len, 0, -1): sides = find_rect(segs, l, tot_len/2-l) if sides is not None: print(sides) return sides print("Can't find any solution") make_rect([4,2,4,4,6,8]) The idea is simple: first, calculate the optimal length (that is, the length to make a square), then search everything starting off with the optimal length, and go down to 1 for one side. For each length, enumerate all sets for one side of the claculated length, then enumerate all sets for the opposite side (of the same length), then if I can find one more set of the remaining length (that is total_len/2 minus the side length I am looking at), then I've got the best solution. This happens in find_rect() function.
Well, I get little bit bored so play around with Java to have some experience, can be poorly coded and without tuning, as I am trying to increase my coding skill, comments are welcome. My computer able to answer me for small arrays:) Output looks like: Largest rectangle range is ; 48 ------------------------------------------------- input values; [ 4,2,4,4,6,8,9 ] ------------------------------------------------- Array details of the rectangle: A1: [ 6 ] B1: [ 8 ] A2: [ 2,4 ] B2: [ 4,4 ] combination.class using Kenneth algorithm; import java.math.BigInteger; public class Combination { /** * Burak */ private int[] a; private int n; private int r; private BigInteger numLeft; private BigInteger total; public Combination (int n, int r) { if (r > n) { throw new IllegalArgumentException (); } if (n < 1) { throw new IllegalArgumentException (); } this.n = n; this.r = r; a = new int[r]; BigInteger nFact = getFactorial (n); BigInteger rFact = getFactorial (r); BigInteger nminusrFact = getFactorial (n - r); total = nFact.divide (rFact.multiply (nminusrFact)); reset (); } //------ // Reset //------ public void reset () { for (int i = 0; i < a.length; i++) { a[i] = i; } numLeft = new BigInteger (total.toString ()); } //------------------------------------------------ // Return number of combinations not yet generated //------------------------------------------------ public BigInteger getNumLeft () { return numLeft; } //----------------------------- // Are there more combinations? //----------------------------- public boolean hasMore () { return numLeft.compareTo (BigInteger.ZERO) == 1; } //------------------------------------ // Return total number of combinations //------------------------------------ public BigInteger getTotal () { return total; } //------------------ // Compute factorial //------------------ private static BigInteger getFactorial (int n) { BigInteger fact = BigInteger.ONE; for (int i = n; i > 1; i--) { fact = fact.multiply (new BigInteger (Integer.toString (i))); } return fact; } //-------------------------------------------------------- // Generate next combination (algorithm from Rosen p. 286) //-------------------------------------------------------- public int[] getNext () { if (numLeft.equals (total)) { numLeft = numLeft.subtract (BigInteger.ONE); return a; } int i = r - 1; while (a[i] == n - r + i) { i--; } a[i] = a[i] + 1; for (int j = i + 1; j < r; j++) { a[j] = a[i] + j - i; } numLeft = numLeft.subtract (BigInteger.ONE); return a; } } And main Combinator.class; import java.util.*; public class Combinator { /** * #param args */ private static int[] ad; private static int[] bd; private static String a1; private static String a2; private static String b1; private static String b2; private static int bestTotal =0; public static void main(String[] args) { int[] array={4,2,4,4,6,8,9}; getBestCombination(array, 1); if(bestTotal <= 0){ System.out.println("System couldnt create any rectangle."); }else{ System.out.println("Largest rectangle range is ; " + bestTotal); System.out.println("-------------------------------------------------"); System.out.println("input values; " + parseArrayToString(array)); System.out.println("-------------------------------------------------"); System.out.println("Array details of the rectangle:"); System.out.println("A1: " + a1); System.out.println("B1: " + b1); System.out.println("A2: " + a2); System.out.println("B2: " + b2); } } private static void getBestCombination(int[] array, int level){ int[] a; int[] b; int bestPerimeter = getTotal(array,true); Vector<Vector<Integer>> results = null; for(int o=array.length-1;o>=1;o--){ for(int u=bestPerimeter;u>=1;u--){ results = Combinator.compute (array, o, u); if(results.size() > 0){ for(int i=0;i<results.size();i++){ a = new int[results.elementAt(i).size()]; for(int j = 0;j<results.elementAt(i).size();j++){ a[j] = results.elementAt(i).elementAt(j); } b = removeItems(array, results.elementAt(i)); if(level == 1){ getBestCombination(a,2); getBestCombination(b,3); }else if(level == 2){ ad = a; bd = b; }else{ getBestCombination(a,4); getBestCombination(b,4); if(getTotal(ad, false) == getTotal(a, false) && getTotal(bd, false) == getTotal(b, false)){ if(bestTotal<(getTotal(ad, false)*getTotal(bd, false))){ bestTotal = getTotal(ad, false)*getTotal(bd, false); a1 = parseArrayToString(ad); a2 = parseArrayToString(a); b1 = parseArrayToString(bd); b2 = parseArrayToString(b); } }else if(getTotal(ad, false) == getTotal(b, false) && getTotal(bd, false) == getTotal(a, false)){ if(bestTotal<(getTotal(ad, false)*getTotal(bd, false))){ bestTotal = getTotal(ad, false)*getTotal(bd, false); a1 = parseArrayToString(ad); a2 = parseArrayToString(b); b1 = parseArrayToString(bd); b2 = parseArrayToString(a); } } } } } } } } private static String parseArrayToString(int[] items){ String s = "[ "; for(int i=0;i<items.length;i++){ if(i!=items.length-1){ s = s + items[i] + ","; }else{ s = s + items[i]; } } s = s + " ]"; return s; } #SuppressWarnings("rawtypes") private static int[] removeItems(int[] array, Vector items){ ArrayList<Integer> res = new ArrayList<Integer>(); for(int i=0;i<array.length;i++){ res.add(array[i]); } for(int u = 0;u<items.size();u++){ res.remove(items.elementAt(u)); } int[] results = new int[res.size()]; for(int o=0;o<res.size();o++){ results[o] = res.get(o); } return results; } private static int getTotal(int[] array,boolean bestPerimeter){ int sum = 0; for (int i = 0; i < array.length; i++) { sum += array[i]; } if(bestPerimeter == true){ if(sum%2!=0){ sum = sum -1; } sum = sum/2; } //System.out.println(sum); return sum; } #SuppressWarnings("rawtypes") private static int getSum (Vector v) { int sum = 0; Integer n; for (int i = 0; i < v.size (); i++) { n = (Integer) v.elementAt(i); sum += n.intValue (); } return sum; } #SuppressWarnings({ "rawtypes", "unchecked" }) public static Vector<Vector<Integer>> compute (int[] array, int atATime, int desiredTotal) { int[] indices; Combination gen = new Combination (array.length, atATime); Vector results = new Vector (); Vector combination; int sum; Integer intObj; while (gen.hasMore ()) { combination = new Vector (); indices = gen.getNext (); for (int i = 0; i < indices.length; i++) { intObj = new Integer (array[indices[i]]); combination.addElement (intObj); } sum = getSum (combination); if (sum == desiredTotal) { Collections.sort (combination); if (!results.contains (combination)) { results.addElement (combination); } } } return results; } }
Help with algorithm problem from SPOJ
I thought it would be a fun problem: Prime Path But...It is hard for me. My only idea is "To do something with knapsack problem".. and no other ideas. Could You track me for good way? It's not for any challenge or University homework. I just want to learn something. _ Ok, but firstly, how to find this prime numbers? Do i need to find all 4digit prime numbers, add it to graph? For now i have generating all prime numbers. http://pastebin.com/wbhRNRHQ Could You give me sample code to declare graph build on neighbour list?
Seems like a straightforward graph path finding problem. Take all 4 digit primes as the vertices. Connect two with an edge, if we can go from one to the other. Now given two, you need to find the shortest path between them, in the graph we just formed. A simple BFS (breadth-first-search) should do for that. For programming contests with time limits, you could even hardcode every possible prime pair path and get close to zero running time!
Build a graph where the nodes are all the 4 digit prime numbers, and there are arcs everywhere two numbers have three digits in common. From there, it's a basic graph traversal to find the lowest-cost path from one node to another.
I came across a similar question where I had to convert one 4 digit prime number 1033 to another 4 digit prime number 3739 in minimum number of steps. I was able to solve the problem, it might not be efficient but here is the working code for the same. Below code has been written in Java import java.util.*; public class PrimeNumberProblem { public static void main(String... args) { System.out.println("Minimum number of steps required for converting 1033 to 3739 are = " + getMinSteps(1033, 3739)); } public static int getMinSteps(int a, int b) { if (a == b) return 0; List<Integer> primes = new ArrayList<>(); // get all the 4 digit prime numbers primes = getPrimeNumbers(); // consists of graph with vertices as all the prime numbers Graph graph = addNumbersToGraph(primes); // adding edges to the graph vertices Graph finalGraph = addWeightToGraph(graph); // min number of steps required int result = findShortestRoute(finalGraph.getVertex(a), finalGraph.getVertex(b)); return result; } private static int findShortestRoute(Vertex source, Vertex dest) { if (source.getVertexValue() == dest.getVertexValue()) return 0; // step 1 Initialize the queue. Also Map to store path Queue<Vertex> visitedQueue = new LinkedList<>(); Map<Vertex, Vertex> currentPrevMap = new HashMap<Vertex, Vertex>(); // step 2 start from visiting S (starting node), and mark it visited, add to queue Map<Integer, Boolean> visited = new HashMap<Integer, Boolean>(); visited.put(source.getVertexValue(), true); visitedQueue.add(source); int level = 0; // step 3 Repeat until queue is empty while (!visitedQueue.isEmpty()) { // step 4 remove from queue Vertex current = visitedQueue.remove(); if (current.getVertexValue() == dest.getVertexValue()) { printPath(source, dest, currentPrevMap); return level; } else if (current.getAdjacentVertices().size() > 0) { level++; } // step 5 add each of the unvisited neighbour and mark visited for (Vertex adjacentVertex : current.getAdjacentVertices()) { Integer value = adjacentVertex.getVertexValue(); if (value == dest.getVertexValue()) { currentPrevMap.put(adjacentVertex, current); printPath(source, dest, currentPrevMap); return level; } if (visited.get(value) == null) { currentPrevMap.put(adjacentVertex, current); // mark visited and enqueue it visited.put(value, true); visitedQueue.add(adjacentVertex); } } } // not found System.out.println("Dest vertex not found"); return -1; } private static void printPath(Vertex source, Vertex dest, Map<Vertex, Vertex> currentPrevMap) { Vertex node = dest; System.out.println("Reverse Path from source: " + source.getVertexValue() + " to dest: " + dest.getVertexValue()); while (node != source) { System.out.println(node.getVertexValue()); node = currentPrevMap.get(node); } System.out.println(source.getVertexValue()); } private static Graph addWeightToGraph(Graph graph) { List<Vertex> vertices = graph.getAllVertices(); for (Vertex i : vertices) { for (Vertex j : vertices) { if (i.equals(j)) continue; if (distance(i, j) == 1) { i.getAdjacentVertices().add(j); // i.addEdge(new Edge(i, j, 1)); } } } return graph; } private static int distance(Vertex source, Vertex dest) { if (source.getVertexValue() == dest.getVertexValue()) { return 0; } char[] numA = extractIntegers(source.getVertexValue()); char[] numB = extractIntegers(dest.getVertexValue()); int len1 = numA.length; int tracker = 0; for (int i = 0; i < len1; i++) { if (numA[i] != numB[i]) { numA[i] = numB[i]; tracker++; String sA = String.copyValueOf(numA); String sB = String.copyValueOf(numB); // if we have reached destination if (Integer.parseInt(sA) == Integer.parseInt(sB)) { return tracker; } } } return tracker; } private static char[] extractIntegers(int i) { char[] arr = Integer.toString(i).toCharArray(); return arr; } private static Graph addNumbersToGraph(List<Integer> primes) { Graph g = new Graph(); for (Integer prime : primes) { g.addVertex(new Vertex(prime)); } return g; } private static List<Integer> getPrimeNumbers() { List<Integer> fourDigitPrimes = new ArrayList<>(); fourDigitPrimes.add(1033); fourDigitPrimes.add(1733); fourDigitPrimes.add(3733); fourDigitPrimes.add(3739); // for (int i = 1000; i < 9999; i++) { // if (isPrime(i)) // fourDigitPrimes.add(i); // } return fourDigitPrimes; } private static boolean isPrime(int i) { for (int k = 2; k < Math.sqrt(i); k++) { if (i % k == 0) return false; } return true; } } class Graph { public List<Vertex> vertexList = new ArrayList<Vertex>(); public void addVertex(Vertex V) { vertexList.add(V); } public List getAllAdjacentNodes(Vertex V) { return V.getAdjacentVertices(); } public List getAllVertices() { return vertexList; } public Vertex getVertex(int val) { Iterator<Vertex> keys = vertexList.iterator(); while (keys.hasNext()) { Vertex v = keys.next(); if (v.getVertexValue() == val) return v; } return null; } } class Vertex { int value; private List<Vertex> adjacentVertices = new ArrayList<Vertex>(); public Vertex(int v) { this.value = v; } public List<Vertex> getAdjacentVertices() { return adjacentVertices; } public int getVertexValue() { return value; } #Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Vertex vertex = (Vertex) o; return value == vertex.value; } #Override public int hashCode() { return value; } }
Look into "breadth-first search". Also worth bearing in mind here that the problem can be approached "from both ends" simultaneously (a chain from numbers X to Y can be reversed to get Y to X, and you can exploit this). Precalculating primes will avoid much computation along the way.
I'd run a BFS using probable prime testing, which would work relatively well with only 4 digit numbers. With only 4 digits, also, you may want to use more exacting methods to produce all primes to compare against for faster prime checking.
Could You give me sample code to declare graph build on neighbour list? here is a sample code for breadth first search public static final int MAX = 10000; boolean[] prime = new boolean[MAX]; int[] dist = new int[MAX]; //get digit i [1 to 4] in num public int getDigit(int num,int i){ return num % ((int)Math.pow(10, i)) / ((int) Math.pow(10, i-1)); } //set digit i to d public int setDigit(int num,int i,int d){ return (num - getDigit(num, i)*(int)Math.pow(10, i-1)) + d * (int)Math.pow(10,i-1); } public int bfs(int start,int end){ Queue<Integer> q = new LinkedList<Integer>(); q.add(start); HashSet<Integer> visited = new HashSet<Integer>(); visited.add(start); dist[start] = 0; int x,y,d = 0; while (q.size() > 0){ x = q.poll(); d = dist[x]; if (x == end) return d; for (int i = 1; i < 5; i++) { //digit number i for (int j = 0; j < 10; j++) { //avoid setting last digit if (j == 0 && i == 4) continue; //set digit number i to j y = setDigit(x, i, j); if (prime[y] && y != x && !visited.contains(y)){ q.add(y); visited.add(y); dist[y] = d + 1; } } } } return -1; }
Here is my solution using BFS and I have already saved all 4 digit prime numbers into an array as there is no need to write a function to calculate the prime numbers. I hope it helps #include<stdio.h> int hash[10000]; int a,b,ans,level,new_num,count; int prime[] = {1009,1013,1019,1021,1031,1033,1039,1049,1051,1061,1063,1069,1087,1091,1093,1097,1103,1109,1117,1123,1129,1151,1153,1163,1171,1181,1187,1193,1201,1213,1217,1223,1229,1231,1237,1249,1259,1277,1279,1283,1289,1291,1297,1301,1303,1307,1319,1321,1327,1361,1367,1373,1381,1399,1409,1423,1427,1429,1433,1439,1447,1451,1453,1459,1471,1481,1483,1487,1489,1493,1499,1511,1523,1531,1543,1549,1553,1559,1567,1571,1579,1583,1597,1601,1607,1609,1613,1619,1621,1627,1637,1657,1663,1667,1669,1693,1697,1699,1709,1721,1723,1733,1741,1747,1753,1759,1777,1783,1787,1789,1801,1811,1823,1831,1847,1861,1867,1871,1873,1877,1879,1889,1901,1907,1913,1931,1933,1949,1951,1973,1979,1987,1993,1997,1999,2003,2011,2017,2027,2029,2039,2053,2063,2069,2081,2083,2087,2089,2099,2111,2113,2129,2131,2137,2141,2143,2153,2161,2179,2203,2207,2213,2221,2237,2239,2243,2251,2267,2269,2273,2281,2287,2293,2297,2309,2311,2333,2339,2341,2347,2351,2357,2371,2377,2381,2383,2389,2393,2399,2411,2417,2423,2437,2441,2447,2459,2467,2473,2477,2503,2521,2531,2539,2543,2549,2551,2557,2579,2591,2593,2609,2617,2621,2633,2647,2657,2659,2663,2671,2677,2683,2687,2689,2693,2699,2707,2711,2713,2719,2729,2731,2741,2749,2753,2767,2777,2789,2791,2797,2801,2803,2819,2833,2837,2843,2851,2857,2861,2879,2887,2897,2903,2909,2917,2927,2939,2953,2957,2963,2969,2971,2999,3001,3011,3019,3023,3037,3041,3049,3061,3067,3079,3083,3089,3109,3119,3121,3137,3163,3167,3169,3181,3187,3191,3203,3209,3217,3221,3229,3251,3253,3257,3259,3271,3299,3301,3307,3313,3319,3323,3329,3331,3343,3347,3359,3361,3371,3373,3389,3391,3407,3413,3433,3449,3457,3461,3463,3467,3469,3491,3499,3511,3517,3527,3529,3533,3539,3541,3547,3557,3559,3571,3581,3583,3593,3607,3613,3617,3623,3631,3637,3643,3659,3671,3673,3677,3691,3697,3701,3709,3719,3727,3733,3739,3761,3767,3769,3779,3793,3797,3803,3821,3823,3833,3847,3851,3853,3863,3877,3881,3889,3907,3911,3917,3919,3923,3929,3931,3943,3947,3967,3989,4001,4003,4007,4013,4019,4021,4027,4049,4051,4057,4073,4079,4091,4093,4099,4111,4127,4129,4133,4139,4153,4157,4159,4177,4201,4211,4217,4219,4229,4231,4241,4243,4253,4259,4261,4271,4273,4283,4289,4297,4327,4337,4339,4349,4357,4363,4373,4391,4397,4409,4421,4423,4441,4447,4451,4457,4463,4481,4483,4493,4507,4513,4517,4519,4523,4547,4549,4561,4567,4583,4591,4597,4603,4621,4637,4639,4643,4649,4651,4657,4663,4673,4679,4691,4703,4721,4723,4729,4733,4751,4759,4783,4787,4789,4793,4799,4801,4813,4817,4831,4861,4871,4877,4889,4903,4909,4919,4931,4933,4937,4943,4951,4957,4967,4969,4973,4987,4993,4999,5003,5009,5011,5021,5023,5039,5051,5059,5077,5081,5087,5099,5101,5107,5113,5119,5147,5153,5167,5171,5179,5189,5197,5209,5227,5231,5233,5237,5261,5273,5279,5281,5297,5303,5309,5323,5333,5347,5351,5381,5387,5393,5399,5407,5413,5417,5419,5431,5437,5441,5443,5449,5471,5477,5479,5483,5501,5503,5507,5519,5521,5527,5531,5557,5563,5569,5573,5581,5591,5623,5639,5641,5647,5651,5653,5657,5659,5669,5683,5689,5693,5701,5711,5717,5737,5741,5743,5749,5779,5783,5791,5801,5807,5813,5821,5827,5839,5843,5849,5851,5857,5861,5867,5869,5879,5881,5897,5903,5923,5927,5939,5953,5981,5987,6007,6011,6029,6037,6043,6047,6053,6067,6073,6079,6089,6091,6101,6113,6121,6131,6133,6143,6151,6163,6173,6197,6199,6203,6211,6217,6221,6229,6247,6257,6263,6269,6271,6277,6287,6299,6301,6311,6317,6323,6329,6337,6343,6353,6359,6361,6367,6373,6379,6389,6397,6421,6427,6449,6451,6469,6473,6481,6491,6521,6529,6547,6551,6553,6563,6569,6571,6577,6581,6599,6607,6619,6637,6653,6659,6661,6673,6679,6689,6691,6701,6703,6709,6719,6733,6737,6761,6763,6779,6781,6791,6793,6803,6823,6827,6829,6833,6841,6857,6863,6869,6871,6883,6899,6907,6911,6917,6947,6949,6959,6961,6967,6971,6977,6983,6991,6997,7001,7013,7019,7027,7039,7043,7057,7069,7079,7103,7109,7121,7127,7129,7151,7159,7177,7187,7193,7207,7211,7213,7219,7229,7237,7243,7247,7253,7283,7297,7307,7309,7321,7331,7333,7349,7351,7369,7393,7411,7417,7433,7451,7457,7459,7477,7481,7487,7489,7499,7507,7517,7523,7529,7537,7541,7547,7549,7559,7561,7573,7577,7583,7589,7591,7603,7607,7621,7639,7643,7649,7669,7673,7681,7687,7691,7699,7703,7717,7723,7727,7741,7753,7757,7759,7789,7793,7817,7823,7829,7841,7853,7867,7873,7877,7879,7883,7901,7907,7919,7927,7933,7937,7949,7951,7963,7993,8009,8011,8017,8039,8053,8059,8069,8081,8087,8089,8093,8101,8111,8117,8123,8147,8161,8167,8171,8179,8191,8209,8219,8221,8231,8233,8237,8243,8263,8269,8273,8287,8291,8293,8297,8311,8317,8329,8353,8363,8369,8377,8387,8389,8419,8423,8429,8431,8443,8447,8461,8467,8501,8513,8521,8527,8537,8539,8543,8563,8573,8581,8597,8599,8609,8623,8627,8629,8641,8647,8663,8669,8677,8681,8689,8693,8699,8707,8713,8719,8731,8737,8741,8747,8753,8761,8779,8783,8803,8807,8819,8821,8831,8837,8839,8849,8861,8863,8867,8887,8893,8923,8929,8933,8941,8951,8963,8969,8971,8999,9001,9007,9011,9013,9029,9041,9043,9049,9059,9067,9091,9103,9109,9127,9133,9137,9151,9157,9161,9173,9181,9187,9199,9203,9209,9221,9227,9239,9241,9257,9277,9281,9283,9293,9311,9319,9323,9337,9341,9343,9349,9371,9377,9391,9397,9403,9413,9419,9421,9431,9433,9437,9439,9461,9463,9467,9473,9479,9491,9497,9511,9521,9533,9539,9547,9551,9587,9601,9613,9619,9623,9629,9631,9643,9649,9661,9677,9679,9689,9697,9719,9721,9733,9739,9743,9749,9767,9769,9781,9787,9791,9803,9811,9817,9829,9833,9839,9851,9857,9859,9871,9883,9887,9901,9907,9923,9929,9931,9941,9949,9967,9973}; int size = sizeof(prime)/sizeof(prime[0]); int bfs(int,int); typedef struct q{ int x, c; } queue; queue qq[10000]; int isprime(int x) { int l,r,m; l=m=0; r=size-1; while (l <= r) { int m = l + (r-l)/2; if (prime[m] == x) return 1; if (prime[m] < x) l = m + 1; else r = m - 1; } return 0; } int bfs(int num1,int num2) { int i,j,k,p,q,n; new_num=p=q=0; i=0; j=1; qq[i].x = num1; qq[i].c = 0; hash[num1] = 1; while(i!=j) { n = qq[i].x; level = qq[i].c; if(n==num2) { count = level; return count; } level++; p = n%1000; for(k=1;k<10;k++) { new_num = (k*1000)+ p; if(isprime(new_num)&&(new_num!=n)&&(!hash[new_num])) { hash[new_num] = 1; qq[j].x = new_num; qq[j].c = level; j++; }} p=q=new_num=0; p = n/1000; q = n%100; for(k=0;k<10;k++) { new_num = (p*1000)+k*100+q; if(isprime(new_num)&&(new_num!=n)&&(!hash[new_num])) { hash[new_num] = 1; qq[j].x = new_num; qq[j].c = level; j++; }} p=q=new_num=0; p = n/100; q = n%10; for(k=0;k<10;k++) { new_num = (p*100)+k*10+q; if(isprime(new_num)&&(new_num!=n)&&(!hash[new_num])) { hash[new_num] = 1; qq[j].x = new_num; qq[j].c = level; j++; }} p=q=new_num=0; p = n/10; for(k=0;k<10;k++) { new_num = (p*10)+k; if(isprime(new_num)&&(new_num!=n)&&(!hash[new_num])) { hash[new_num] = 1; qq[j].x = new_num; qq[j].c = level; j++; }} p=q=new_num=0; i++; } return -1;} int main() { int v,tc; setbuf(stdout,NULL); scanf("%d",&tc); for(v=1;v<=tc;v++) { int i,j; a=b=ans=level=new_num=count=0; for(i=0;i<10000;i++) {qq[i].x=0; qq[i].c=0; hash[i]=0;} scanf("%d%d",&a,&b); if(a==b) { ans = 0;} else { ans = bfs(a,b);} printf("Case #%d\n", v); if(ans==-1) { printf("Impossible\n"); } else {printf("%d\n",ans);} } return 0; }
My Python solution using BFS: import queue # Class to represent a graph class Graph: def __init__(self, V): self.V = V # No. of vertices self.prime_list = [[] for i in range(V)] # function to add an edge to graph def addedge(self, V1, V2): self.prime_list[V1].append(V2) self.prime_list[V2].append(V1) def bfs(self, in1, in2): visited = [0] * self.V que = queue.Queue() visited[in1] = 1 que.put(in1) while not que.empty(): prime_index = que.get() i = 0 while i < len(self.prime_list[prime_index]): if not visited[self.prime_list[prime_index][i]]: visited[self.prime_list[prime_index][i]] = visited[prime_index] + 1 que.put(self.prime_list[prime_index][i]) if self.prime_list[prime_index][i] == in2: return visited[self.prime_list[prime_index][i]] - 1 i += 1 # // Finding all 4 digit prime numbers def SieveOfEratosthenes(v): # Create a boolean array "prime[0..n]" and initialize all entries it as true. A value in prime[i] will be # finally be false if i is Not a prime, else true. n = 9999 prime = [True] * (n + 1) p = 2 while p * p <= 9999: if prime[p]: i = p * p while i <= 9999: prime[i] = False i = i + p p = p + 1 # v = [] for i in range(1000, n + 1): if prime[i]: v.append(i) return v def compare(a, b): diff = 0 while a: if a % 10 != b % 10: diff += 1 a //= 10 b //= 10 # If the numbers differ only by a single # digit return true else false if diff > 1: return False return True def shortestPath(num1, num2): # Generate all 4 digit pset = [] SieveOfEratosthenes(pset) # Create a graph where node numbers # are indexes in pset[] and there is # an edge between two nodes only if # they differ by single digit. g = Graph(len(pset)) for i in range(len(pset)): for j in range(i + 1, len(pset)): if compare(pset[i], pset[j]): g.addedge(i, j) # Since graph nodes represent indexes # of numbers in pset[], we find indexes of num1 and num2. in1, in2 = None, None for j in range(len(pset)): if pset[j] == num1: in1 = j for j in range(len(pset)): if pset[j] == num2: in2 = j return g.bfs(in1, in2) # Driver code if __name__ == '__main__': num1 = 1033 num2 = 8179 print(shortestPath(num1, num2))