I have n bags of candies such that no two bags have the same number of candies inside (i.e. it's a set A[] = {a0,a1,a2,...,ai,...,aj} where ai != aj).
I know how many candies is in each bag and the total number M of candies I have.
I need to divide the bags among three children so that the candies are distributed as fairly as possible (i.e. each child gets as close to M/3 as possible).
Needless to say, I may not tear into the bags to even out the counts -- then the question would be trivial.
Does anyone have any thoughts how to solve this -- preferably in Java?
EDIT:
the interviewer wanted me to use a 2-D array to solve the problem: the first kid gets x, the second kid y, the third gets the rest: S[x][y].
This after I tried following:
1] sort array n lg n
2] starting with largest remaining bag, give bag to kid with fewest candy.
Here is my solution for partitioning to two children (it is the correct answer). Maybe it will help with getting the 3-way partition.
int evenlyForTwo(int[] A, int M) {
boolean[] S = new boolean[M+1];
S[0]=true;//empty set
for(int i=0; i<A.length; i++)
for(int x=M; x >= A[i]; x--)
if(!S[x])
S[x]=S[x-A[i]];
int k = (int) M/2;
while(!S[k])
k--;
return k;//one kid gets k the other the rest.
}//
The problem you describe is known as the 3-Partition problem and is known to be NP-hard. The problem is discussed a bit on MathOverflow. You might find some of the pointers there of some value.
Here is a little solution, crude but gives correct results. And you can even change the number of children, bags, etc.
public class BagOfCandies {
static public void main(String...args) {
int repeat = 10;
int childCount = 3;
int bagsCount = childCount + (int) (Math.random() * 10);
for (int k=0; k<repeat; k++) {
int candyCount = 0, n=0;
int[] bags = new int[bagsCount];
for (int i=0; i<bags.length; i++) {
n += 1 + (int) (Math.random() * 2);
bags[i] = n;
candyCount += n;
}
shuffle(bags); // completely optional! It works regardless
boolean[][] dist = divideBags(bags, childCount);
System.out.println("Bags of candy : " + Arrays.toString(bags) + " = " + bags.length);
System.out.println("Total calculated candies is " + candyCount);
int childCandySum = 0;
for (int c=0; c<childCount; c++) {
int childCandies = countSumBags(bags, dist[c]);
System.out.println("Child " + (c+1) + " = " + childCandies + " --> " + Arrays.toString(dist[c]));
childCandySum += childCandies;
}
System.out.println("For a total of " + childCandySum + " candies");
System.out.println("----------------");
}
}
static private void shuffle(int[] bags) {
for (int i=0, len=bags.length; i<len; i++) {
int a = (int)Math.floor(Math.random()*len);
int b = (int)Math.floor(Math.random()*len);
int v = bags[a];
bags[a] = bags[b];
bags[b] = v;
}
}
static private boolean[][] divideBags(int[] bags, int childCount) {
int bagCount = bags.length;
boolean[][] dist = new boolean[childCount][bagCount];
for (int c=0; c<childCount; c++)
Arrays.fill(dist[c], false);
for (int i=0; i<bagCount; i+=childCount)
for (int j=i, c=0; c<childCount && j<bagCount; j++, c++)
dist[c][j] = true;
if (childCount == 1) return dist; // shortcut here
int sumDiff = 1;
int oldDiff = 0;
while (sumDiff != oldDiff) {
oldDiff = sumDiff;
sumDiff = 0;
// start comparing children in pair
for (int child1=0; child1<childCount-1; child1++) {
for (int child2=child1+1; child2<childCount; child2++) {
int count1 = countSumBags(bags, dist[child1]);
int count2 = countSumBags(bags, dist[child2]);
int diff = Math.abs(count1 - count2);
// a difference less than 2 is negligeable
if (diff > 1) {
// find some bags with can swap to even their difference
int c1=-1, c2=-1, cdiff;
boolean swap = false;
for (int i=0; i<bagCount-1; i++) {
for (int j=i; j<bagCount; j++) {
if (dist[child1][i] && dist[child2][j]) {
cdiff = Math.abs((count1 - bags[i] + bags[j]) - (count2 + bags[i] - bags[j]));
if (cdiff < diff) {
c1 = i; c2 = j;
diff = cdiff;
swap = true;
}
}
if (dist[child1][j] && dist[child2][i]) {
cdiff = Math.abs((count1 - bags[j] + bags[i]) - (count2 + bags[j] - bags[i]));
if (cdiff < diff) {
c1 = j; c2 = i;
diff = cdiff;
swap = true;
}
}
}
}
if (swap) {
//System.out.println("Swaping " + c1 + " with " + c2);
dist[child1][c1] = false; dist[child1][c2] = true;
dist[child2][c1] = true; dist[child2][c2] = false;
}
}
//System.out.println("Diff between " + child1 + "(" + countSumBags(bags, dist[child1]) + ") and " + child2 + "(" + countSumBags(bags, dist[child2]) + ") is " + diff);
sumDiff += diff;
}
}
//System.out.println("oldDiff="+oldDiff+", sumDiff="+sumDiff);
}
return dist;
}
static private int countSumBags(int[] bags, boolean[] t) {
int count = 0;
for (int i=0; i<t.length; i++) {
if (t[i]) {
count+=bags[i];
}
}
return count;
}
}
I don't know if this the result you were looking for, but it seems to be, from my understanding of the question.
Related
So in my advanced algorithms class, we are to write an algorithm for a program to find two numbers in two sorted arrays of integers. The format is A[i] + B[j] == x. The runtime of the algorithm needs to be O(n).
I thought i had it and wanted to check so I emailed my professor and she told me my runtime was O(n^2). Here is my code:
int[] A = {1,2,3,4,5};
int[] B = {1,2,3,4,5,6};
int x = 4;
int i = 0;
int j = 0;
for(int n = 0; n < (A.length*B.length); n++) {
if(i >= A.length)
i = 0;
if(n % B.length == 0)
j++;
if(A[i] + B[j] == x) {
System.out.println(A[i] + " + " + B[j] + " = " + x);
break;
}
i++;
}
EDIT
I do apologize if this is still incorrect. I never really grasped the concept of Big-Oh. Would this change the runtime to O(n)? I got rid of the A.length*B.length and tried something a little different.
int[] A = {1,2,3,4,5};
int[] B = {1,2,3,4,5};
int x = 5;
int i = 0;
int j = 0;
while(i < A.length) {
if(B[j] == x - A[i]) {
/* exit */ }
if(j >= B.length) {
j = 0;
i++; }
j++;
}
Solution 1:
Add all values in B to a Map with B value as the map key, and B-index as the map value.
Iterate A, and calculate desired B value as B = x - A. Look for it in the map, and if found, you then have the index.
You will only iterate A and B once each. Adding a single value to map is O(1), and looking up a value is O(1), assuming a HashMap, so overall is O(n).
Solution 2:
Iterate A ascending, and B descending.
For each value in A, look at current B value. Walk down B until A + B <= x (or you reach beginning of B).
You will only iterate A and B once each, so O(n).
Solution 2 requires less memory (no map), and is likely faster (no time spent building map).
UPDATE Here is code:
The above descriptions were based on need for index of values, and the code for each solution is:
Solution 1
private static void findSum(int[] a, int[] b, int x) {
Map<Integer, Integer> bIdx = new HashMap<>();
for (int j = 0; j < b.length; j++)
bIdx.put(b[j], j);
for (int i = 0; i < a.length; i++) {
Integer j = bIdx.get(x - a[i]);
if (j != null)
System.out.println("a[" + i + "] + b[" + j + "] = " + a[i] + " + " + b[j] + " = " + x);
}
}
Solution 2
private static void findSum(int[] a, int[] b, int x) {
for (int i = 0, j = b.length - 1, sum; i < a.length && j >= 0; i++) {
while (j >= 0 && (sum = a[i] + b[j]) >= x) {
if (sum == x)
System.out.println("a[" + i + "] + b[" + j + "] = " + a[i] + " + " + b[j] + " = " + x);
j--;
}
}
}
Test
int[] a = {1,2,3,4,5};
int[] b = {1,2,3,4,5,6};
findSum(a, b, 4);
Output (same from both)
a[0] + b[2] = 1 + 3 = 4
a[1] + b[1] = 2 + 2 = 4
a[2] + b[0] = 3 + 1 = 4
Solution 1 using Set
If you don't need index position, then a Set is better for solution 1:
private static void findSum(int[] aArr, int[] bArr, int x) {
Set<Integer> bSet = new HashSet<>();
for (int b : bArr)
bSet.add(b);
for (int a : aArr)
if (bSet.contains(x - a))
System.out.println(a + " + " + (x - a) + " = " + x);
}
Output
1 + 3 = 4
2 + 2 = 4
3 + 1 = 4
Here is an example of how you can measure your time, i've included another method to find the numbers you mentioned. See the difference in runtime:
int[] A = {1,2,3,4,5};
int[] B = {1,2,3,4,5,6};
int x = 4;
int i = 0;
int j = 0;
long t1 = System.nanoTime();
for(int n = 0; n < (A.length*B.length); n++) {
if(i >= A.length)
i = 0;
if(n % B.length == 0)
j++;
if(A[i] + B[j] == x) {
System.out.println(A[i] + " + " + B[j] + " = " + x);
break;
}
i++;
}
long t2 = System.nanoTime();
System.out.println("Time 1: "+(t2-t1));
//Here's the other method
long t3 = System.nanoTime();
for (int n = 0;n<B.length;n++){
for (int m =0;m<A.length;m++){
if(A[m]+B[n]==x){
System.out.println(A[m] +" + "+B[n] +" = "+ x);
}
}
}
long t4 = System.nanoTime();
System.out.println("Time 2: "+(t4-t3));
Here is the code, for Andreas's Solution 1, that I came up with:
int[] A = {2,3,4};
int[] B = {7,9};
Map<Integer, Integer> hashMap = new HashMap<Integer, Integer>();
int x = 10;
int b;
for(int i = 0; i < B.length; i++) {
hashMap.put(B[i], i);
}
for (int n = 0; n < A.length; n++){
b = x - A[n];
if(hashMap.get(b) != null)
System.out.println(A[n] + " + " + b + " = " + x);
}
I use Java implemented Held-KarpTSP algorithm algo to solve a 25 cities TSP problem.
The program passes with 4 cities.
When it runs with 25 cities it won't stop for several hours. I use jVisualVM to see what's the hotspot, after some optimization now it shows
98% of time is in real computing instead in Map.contains or Map.get.
So I'd like to have your advice, and here is the code:
private void solve() throws Exception {
long beginTime = System.currentTimeMillis();
int counter = 0;
List<BitSetEndPointID> previousCosts;
List<BitSetEndPointID> currentCosts;
//maximum number of elements is c(n,[n/2])
//To calculate m-set's costs just need to keep (m-1)set's costs
List<BitSetEndPointID> lastKeys = new ArrayList<BitSetEndPointID>();
int m;
if (totalNodes < 10) {
//for test data, generate them on the fly
SetUtil3.generateMSet(totalNodes);
}
//m=1
BitSet beginSet = new BitSet();
beginSet.set(0);
previousCosts = new ArrayList<BitSetEndPointID>(1);
BitSetEndPointID beginner = new BitSetEndPointID(beginSet, 0);
beginner.setCost(0f);
previousCosts.add(beginner);
//for m=2 to totalNodes
for (m = 2; m <= totalNodes; m++) {// sum(m=2..n 's C(n,m)*(m-1)(m-1)) ==> O(n^2 * 2^n)
//pick m elements from total nodes, the element id is the index of nodeCoordinates
// the first node is always present
BitSet[] msets;
if (totalNodes < 10) {
msets = SetUtil3.msets[m - 1];
} else {
//for real data set, will read from serialized file
msets = SetUtil3.getMsets(totalNodes, m-1);
}
currentCosts = new ArrayList<BitSetEndPointID>(msets.length);
//System.out.println(m + " sets' size: " + msets.size());
for (BitSet mset : msets) { //C(n,m) mset
int[] candidates = allSetBits(mset, m);
//mset is a BitSet which makes sure begin point 0 comes first
//so end point candidate begins with 1. candidate[0] is always begin point 0
for (int i = 1; i < candidates.length; i++) { // m-1 bits are set
//set the new last point as j, j must not be the same as begin point 0
int j = candidates[i];
//middleNodes = mset -{j}
BitSet middleNodes = (BitSet) mset.clone();
middleNodes.clear(j);
//loop through all possible points which are second to the last
//and get min(A[S-{j},k] + k->j), k!=j
float min = Float.MAX_VALUE;
int k;
for (int ki = 0; ki < candidates.length; ki++) {// m-1 calculation
k = candidates[ki];
if (k == j) continue;
float middleCost = 0;
BitSetEndPointID key = new BitSetEndPointID(middleNodes, k);
int index = previousCosts.indexOf(key);
if (index != -1) {
//System.out.println("get value from map in m " + m + " y key " + middleNodes);
middleCost = previousCosts.get(index).getCost();
} else if (k == 0 && !middleNodes.equals(beginSet)) {
continue;
} else {
System.out.println("middleCost not found!");
continue;
// System.exit(-1);
}
float lastCost = distances[k][j];
float cost = middleCost + lastCost;
if (cost < min) {
min = cost;
}
counter++;
if (counter % 500000 == 0) {
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException iex) {
System.out.println("Who dares interrupt my precious sleep?!");
}
}
}
//set the costs for chosen mset and last point j
BitSetEndPointID key = new BitSetEndPointID(mset, j);
key.setCost(min);
currentCosts.add(key);
// System.out.println("===========================================>mset " + mset + " and end at " +
// j + " 's min cost: " + min);
// if (m == totalNodes) {
// lastKeys.add(key);
// }
}
}
previousCosts = currentCosts;
System.out.println("...");
}
calcLastStop(lastKeys, previousCosts);
System.out.println(" cost " + (System.currentTimeMillis() - beginTime) / 60000 + " minutes.");
}
private void calcLastStop(List<BitSetEndPointID> lastKeys, List<BitSetEndPointID> costs) {
//last step, calculate the min(A[S={1..n},k] +k->1)
float finalMinimum = Float.MAX_VALUE;
for (BitSetEndPointID key : costs) {
float middleCost = key.getCost();
Integer endPoint = key.lastPointID;
float lastCost = distances[endPoint][0];
float cost = middleCost + lastCost;
if (cost < finalMinimum) {
finalMinimum = cost;
}
}
System.out.println("final result: " + finalMinimum);
}
You can speed up your code by using arrays of primitives (it's likely to have to better memory layout than a list of objects) and operating on bitmasks directly (without bitsets or other objects). Here is some code (it generates a random graph but you can easily change it so that it reads your graph):
import java.io.*;
import java.util.*;
class Main {
final static float INF = 1e10f;
public static void main(String[] args) {
final int n = 25;
float[][] dist = new float[n][n];
Random random = new Random();
for (int i = 0; i < n; i++)
for (int j = i + 1; j < n; j++)
dist[i][j] = dist[j][i] = random.nextFloat();
float[][] dp = new float[n][1 << n];
for (int i = 0; i < dp.length; i++)
Arrays.fill(dp[i], INF);
dp[0][1] = 0.0f;
for (int mask = 1; mask < (1 << n); mask++) {
for (int lastNode = 0; lastNode < n; lastNode++) {
if ((mask & (1 << lastNode)) == 0)
continue;
for (int nextNode = 0; nextNode < n; nextNode++) {
if ((mask & (1 << nextNode)) != 0)
continue;
dp[nextNode][mask | (1 << nextNode)] = Math.min(
dp[nextNode][mask | (1 << nextNode)],
dp[lastNode][mask] + dist[lastNode][nextNode]);
}
}
}
double res = INF;
for (int lastNode = 0; lastNode < n; lastNode++)
res = Math.min(res, dist[lastNode][0] + dp[lastNode][(1 << n) - 1]);
System.out.println(res);
}
}
It takes only a couple of minutes to complete on my computer:
time java Main
...
real 2m5.546s
user 2m2.264s
sys 0m1.572s
I'm trying to solve an "Almost Sorted" challenge in hackerrank the problem is:
Given an array with elements, can you sort this array in ascending order using only one of the following operations?
Swap two elements.
Reverse one sub-segment.
Input Format
The first line contains a single integer, , which indicates the size of the array.
The next line contains integers separated by spaces.
Sample Input #1
2
4 2
Sample Output #1
yes
swap 1 2
Sample Input #2
3
3 1 2
Sample Output #2
no
Sample Input #3
6
1 5 4 3 2 6
Sample Output #3
yes
reverse 2 5
I tried to solve the challenge and my code is working but it seems it's to slow for big arrays.
Kindly asking you to help me to find a better solution for mentioned problem.
Below is my code:
import java.util.*;
public class Solution
{
private static int[] arr;
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
int N = in.nextInt();
arr = new int[N];
for (int i = 0; i < N; i++)
{
arr[i] = in.nextInt();
}
if (IsSorted(arr))
{
System.out.println("yes");
return;
}
if(CheckSingleSwap(arr))
return;
if(CheckSingleReverse(arr))
return;
System.out.println("no");
}
private static boolean CheckSingleReverse(int[] arr)
{
int length = arr.length;
int limit = length - 2;
int current = 1;
List<Integer> indexes = new ArrayList<Integer>();
while (current < limit)
{
for (int i = 0; i < length; i++)
{
int temp = current + i;
for (int j = i; j <= temp && temp < length; j++)
{
indexes.add(j);
}
if (IsSorted(ReverseArrayPart(arr, indexes)))
{
System.out.println("yes");
System.out.println("reverse " + (indexes.get(0) + 1) + " " + (indexes.get(indexes.size() - 1) + 1));
return true;
}
indexes.clear();
}
current++;
}
return false;
}
private static int[] ReverseArrayPart(int[] arr, List<Integer> indexes)
{
int[] result = new int[arr.length];
int[] arrayPart = new int[indexes.size()];
int j = 0;
for (int i = 0; i < arr.length; i++)
{
if (indexes.contains(i))
{
arrayPart[j] = arr[i];
j++;
}
result[i] = arr[i];
}
for(int i = 0; i < arrayPart.length / 2; i++)
{
int temp = arrayPart[i];
arrayPart[i] = arrayPart[arrayPart.length - i - 1];
arrayPart[arrayPart.length - i - 1] = temp;
}
j = 0;
for (int i = 0; i < result.length; i++)
{
if (indexes.contains(i))
{
result[i] = arrayPart[j];
j++;
}
}
return result;
}
private static boolean CheckSingleSwap(int[] arr)
{
int count = 0;
int[] B = Arrays.copyOf(arr, arr.length);
Arrays.sort(B);
List<Integer> indexes = new ArrayList<Integer>();
for(int i = 0; i < arr.length; i++)
{
if(arr[i] != B[i])
{
count++;
indexes.add(i+1);
}
}
if(count > 2)
return false;
System.out.println("yes");
System.out.println("swap " + indexes.get(0) + " " + indexes.get(1));
return true;
}
private static boolean IsSorted(int[] arr)
{
int length = arr.length;
for (int i = 0; i < length - 1; i++)
{
if (arr[i] > arr[i + 1])
{
return false;
}
}
return true;
}
}
For the following code, pass in A as the original array and B as the sorted array.
CheckSingleSwap:
Instead of adding the indices to another list, store the first swap you encounter, and keep going; if you find the corresponding other swap, then store it and record the finding; if you find a different swap, exit with false. At the end if you've recorded the finding, print the corresponding indices.
private static boolean CheckSingleSwap(int[] A, int[] B)
{
int L = A.length;
int firstSwap = -1, secondSwap = -1;
for(int i = 0; i < L; i++)
{
if(A[i] != B[i])
{
if (firstSwap == -1)
firstSwap = i;
else if (secondSwap == -1 && A[i] == B[firstSwap] && A[firstSwap] == B[i])
secondSwap = i;
else
return false;
}
}
if (firstSwap != -1 && secondSwap != -1)
{
System.out.println("yes");
System.out.println("swap " + (firstSwap + 1) + " " + (secondSwap + 1));
return true;
}
System.out.println("array is already sorted!");
return false; // or whatever you decide to do; maybe even an exception or enumerated type
}
CheckSingleReverse:
You are doing WAY too much here! You seem to be brute forcing every single possible case (at first glance).
What you can do instead is to find the region where all the numbers are different. If there are more than two of these, or two which are separated by more than one element, then return false immediately.
The reason for the "more than one" thing above is because of odd-number length regions - the middle element would be the same. If you find such two regions, treat them as one. Then you can proceed to find out if the region is reversed.
private static boolean CheckSingleReverse(int[] A, int[] B)
{
// find region
int L = A.length;
int diffStart = -1, diffEnd = -1; boolean mid = false, found = false;
for (int i = 0; i < L; i++)
{
if (A[i] != B[i])
{
if (found)
{
if (i - diffEnd == 2 && !mid)
{
mid = true;
found = false;
diffEnd = -1;
}
else
return false;
}
else if (diffStart == -1)
diffStart = i;
}
else
if (diffStart != -1 && diffEnd == -1)
{
found = true;
diffEnd = i - 1;
}
}
if (diffEnd == -1)
{
if (A[L - 1] != B[L - 1])
diffEnd = L - 1;
else if (!found)
{
System.out.println("array is already sorted!");
return false;
}
}
// find out if it's reversed
int count = (diffEnd - diffStart + 1) / 2;
for (int i = 0; i < count; i++)
{
int oneEnd = diffStart + i, otherEnd = diffEnd - i;
if (!(A[oneEnd] == B[otherEnd] && A[otherEnd] == B[oneEnd]))
return false;
}
System.out.println("yes");
System.out.println("reverse " + (diffStart + 1) + " " + (diffEnd + 1));
return true;
}
Just to give you an idea of the performance boost, on ideone.com, with an array length of 150, the original implementation of CheckSingleReverse took 1.83 seconds, whereas the new one took just 0.1 seconds. With a length of 250, the original actually exceeded the computational time limit (5 seconds), whereas the new one still took just 0.12 seconds.
From this it would seem that your implementation takes exponential time, whereas mine is linear time (ignoring the sorting).
Funnily enough, with an array size of 3 million I'm still getting around 0.26 seconds (ideone's execution time fluctuates a bit as well, probs due to demand)
I am trying to solve the following problem:
Find the largest palindrome made from the product of two 3-digit numbers.
I have the following Java code:
public static void main(String[] args) {
int a = 999, b = 999;
for(int i = 100; i <= a; i++) {
for(int j = 100; j <= b; j++) {
checkPalindrome(i*j, i, j);
}
}
}
public static void checkPalindrome(int n, int a, int b) {
String s = "" + n;
boolean palindrome = false;
int j = s.length()-1;
for(int i = 0; i < s.length(); i++){
if(s.charAt(i) != s.charAt(j))
break;
j -= i;
}
if(palindrome)
System.out.println(n + ", " + a + ", " + b);
}
I'm still lacking the change of the "palindrome" variable but at the moment if I run it I get a String index out of range on line 28 which is the j -= i I just don't understand why this is happening I mean, I get that the difference is resulting in a number lower than 0 but I can't figure out WHY it happens. Could someone please explain me?
Your method can be improved like this. The condition in for loop i<=j reduced number of iterations too.
public static void checkPalindrome(int n, int a, int b) {
String s = "" + n;
boolean palindrome = false;
int j = s.length()-1;
for(int i = 0; i <= j; i++){
if(s.charAt(i) != s.charAt(j))
break;
j --;
}
if(palindrome)
System.out.println(n + ", " + a + ", " + b);
}
Hope this helps.
I think you want j-- not j -= i. Especially since i starts at 0.
change your code to:
public static void checkPalindrome(int n, int a, int b) {
String s = "" + n;
boolean palindrome = true;
int j = s.length()-1;
for(int i = 0; i < s.length(); i++){
if(s.charAt(i) != s.charAt(j))
palindrome = false;
}
if(palindrome)
System.out.println(n + ", " + a + ", " + b);
}
You're incrementing i - you want to decrement j - you DON'T want to do j -= i.
Otherwise for a string of length 5, you'd get:
i = 0, j = 4
i = 1, j = 4
i = 2 , j = 3
i = 3 , j = 1
i = 4, j = -2
Though if it's giving an index out of range message, you're running a different version of the code - j -= i can't possibly generate that.
OK, I have this problem to solve but I can’t program it in Java correctly. See the picture below, you’ll see a 6 pointed star were every point and intersection of lines is a letter.
The assignment is to position the numbers 1 to 12 in such a way that the sum of all lines of four balls is 26 and the sum of all the 6 points of the star is 26 as well.
This comes down to:
(A+C+F+H==26)
(A+D+G+K==26)
(B+C+D+E==26)
(B+F+I+L==26)
(E+G+J+L==26)
(H+I+J+K==26)
(A+B+E+H+K+L==26)
So I started programming a program that would loop through all options brute forcing a solution. The loop is working, however, it now shows solutions where one number is used more than once, which is not allowed. How can I make it in the code that it also checks whether all variables are different or not?
if ((A!= B != C != D != E != F != G != H != I != J != K != L)
I tried the above, but it doesn't work, because it says:
incomparable types: boolean and int.
How can I make a check within 1 or a small statement for whether or not all the numbers are different?
(instead of making a nested 12*12 statement which checks every variable combination)
This is my code so far:
public class code {
public static void main(String[] args){
for(int A = 1; A < 13; A++){
for(int B = 1; B < 13; B++){
for(int C = 1; C < 13; C++){
for(int D = 1; D < 13; D++){
for(int E = 1; E < 13; E++){
for(int F = 1; F < 13; F++){
for(int G = 1; G < 13; G++){
for(int H = 1; H < 13; H++){
for(int I = 1; I < 13; I++){
for(int J = 1; J < 13; J++){
for(int K = 1; K < 13; K++){
for(int L = 1; L < 13; L++){
if ((A+C+F+H==26) && (A+D+G+K==26) && (B+C+D+E==26) && (B+F+I+L==26) && (E+G+J+L==26) && (H+I+J+K==26) && (A+B+E+H+K+L==26)){
if ((A= C != D != E != F != G != H != I != J != K != L)){
System.out.println("A: " + A);
System.out.println("B: " + B);
System.out.println("C: " + C);
System.out.println("D: " + D);
System.out.println("E: " + E);
System.out.println("F: " + F);
System.out.println("G: " + G);
System.out.println("H: " + H);
System.out.println("I: " + I);
System.out.println("J: " + J);
System.out.println("K: " + K);
System.out.println("L: " + L);
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
If I get it correctly, you want to check if all A to L are unique. So just put them in a set and find the size of the set:
if ((new HashSet<Integer>(
Arrays.asList(A, B, C, D, E, F, G, H, I, J, K, L)))
.size() == 12) {
//do your stuff
}
I strongly advise using recursion instead, which would vastly simplify the code. Do something like this:
function generate(set used, array list):
if list.size() == 12:
if list matches criteria:
yield list as solution
else:
for next = 1; next < 13; next++:
if next not in used:
used.add(next)
generate(used, list + next)
used.remove(next)
However, to answer you question directly: You can throw all the values into a set and check that it's size is equal to the number of items you threw in. This works because a set will count duplicates as one.
Before looking for a good solution for you, I would like to help with the error you get.
if ((A= C != D != E != F != G != H != I != J != K != L)){
This line does not makes much sense. The first thing the compiler will check is:
if (A=C)
You probably wanted to code if (A!=C), but let's consider what you really type. A=C is an attribution, so A will receive C value.
Then, the compiler will go on. After attributing C's value to A, it will check the comparison:
if (A=C != D)
This will compare A's value to D, which will result in a boolean -- let's say that the result is false.
The next comparison would be:
if (false != E)
At this point, there is a comparison between a boolean and an int, hence the error incomparable types: boolean and int..
Well, as you need to check wheter your numbers are unique, a nice solution would be the one proposed by #abhin4v.
Your nested loops will execute 12^12 = 8.91610045E12 IF-Statements, many of them invalid because of wrong combinations of numbers. You need permutations of 1,2,3,..,12 as candidates of your bruteforcing approach. The number of permutations of 12 Elements is 12!= 479 001 600, so the bruteforcing will be much faster I guess. With only generating valid permutations you don't need any check for valid combinations.
Here is some sample code, the code in nextPerm() is copied and modified from Permutation Generator :
import java.util.Arrays;
public class Graph26 {
private static final int A = 0;
private static final int B = 1;
private static final int C = 2;
private static final int D = 3;
private static final int E = 4;
private static final int F = 5;
private static final int G = 6;
private static final int H = 7;
private static final int I = 8;
private static final int J = 9;
private static final int K = 10;
private static final int L = 11;
private final static boolean rule1(final int[] n) {
return n[A] + n[C] + n[F] + n[H] == 26;
}
private final static boolean rule2(final int[] n) {
return n[A] + n[D] + n[G] + n[K] == 26;
}
private final static boolean rule3(final int[] n) {
return n[H] + n[I] + n[J] + n[K] == 26;
}
private final static boolean rule4(final int[] n) {
return n[B] + n[C] + n[D] + n[E] == 26;
}
private final static boolean rule5(final int[] n) {
return n[B] + n[F] + n[I] + n[L] == 26;
}
private final static boolean rule6(final int[] n) {
return n[E] + n[G] + n[J] + n[L] == 26;
}
private final static boolean rule7(final int[] n) {
return n[A] + n[B] + n[E] + n[H] + n[K] + n[L] == 26;
}
private final static boolean isValid(final int[] nodes) {
return rule1(nodes) && rule2(nodes) && rule3(nodes) && rule4(nodes)
&& rule5(nodes) && rule6(nodes) && rule7(nodes);
}
class Permutation {
private final int[] o;
private boolean perms = true;
public boolean hasPerms() {
return perms;
}
Permutation(final int[] obj) {
o = obj.clone();
}
private int[] nextPerm() {
int temp;
int j = o.length - 2;
while (o[j] > o[j + 1]) {
j--;
if (j < 0) {
perms = false;
break;
}
}
if (perms) {
int k = o.length - 1;
while (o[j] > o[k]) {
k--;
}
temp = o[k];
o[k] = o[j];
o[j] = temp;
int r = o.length - 1;
int s = j + 1;
while (r > s) {
temp = o[s];
o[s] = o[r];
o[r] = temp;
r--;
s++;
}
}
return o.clone();
}
}
public static void main(final String[] args) {
int[] nodes = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
final Graph26 graph = new Graph26();
final Permutation p = graph.new Permutation(nodes);
int i = 0;
while (p.hasPerms()) {
if (isValid(nodes)) {
System.out.println(Arrays.toString(nodes));
}
i++;
nodes = p.nextPerm();
}
System.out.println(i);
}
}