Find shortest flying time to destination array Java - java

So I have been assigned this monster program
public class AirlineRoutes
{
private int[][] routes;
/**
* Creates a table with direct flight times for a group of cities.
*/
public AirlineRoutes(int[][] routes)
{
this.routes = routes;
}
/**
* Returns the shortest flying time from start to destination
* going through at most one intermediate city.
* #precondition 1 <= start <= N (where N is size of matrix)
* #precondition 1 <= destination <= N (where N is size of matrix)
* Note that cities are labeled 1 to N , whereas the matrix
* is indexed from 0 to N-1
* #param start the city to start the flight from
* #param destination the city to end the flight at
* #return returns the least number of hours going from start
* city to destination. The flight can be direct or
* have a stop in one other city - Destination travleing
* through at most one intermediate city.
*/
public int minTime(int start, int destination)
{
}
/**
* Returns a string containing a chart showing the times
* to each city in hours.
* #return a table showing the time in hours for direct
* flights from every city.
*/
public String toString()
{
String s = "\t\t\tDestination City\n\t\t";
s += "\n\t\t\t";
for (int k = 1; k <= routes[0].length; k++)
s += "\t" + k;
s += "\n\t\t";
for (int k = 0; k <= routes[0].length; k++)
s += "----";
s += "-\n";
for (int r = 0; r < routes[0].length; r++)
{
if (r == 1)
s += "Start";
else if (r == 2)
s += "City";
else
s += "\t";
s += "\t" + (r+1) + "\t|\t";
for (int c = 0; c < routes[r].length; c++)
s += routes[r][c] + "\t";
s += "\n";
}
return s;
}
}
public class AirlineRoutesDriver
{
public static void main(String[] args)
{
int[][] routes = new int[4][4];
for (int k = 0; k < routes.length; k++)
routes[k][k] = 0;
routes[0][1] = 3;
routes[0][2] = 2;
routes[0][3] = 6;
routes[1][0] = 3;
routes[1][2] = 1;
routes[1][3] = 3;
routes[2][0] = 2;
routes[2][1] = 1;
routes[2][3] = 5;
routes[3][0] = 5;
routes[3][1] = 4;
routes[3][2] = 2;
AirlineRoutes r = new AirlineRoutes(routes);
System.out.println(r);
System.out.println("From city 4 to city 1 takes " + r.minTime(4,1) + " hours");
System.out.println("From city 1 to 3 to city " + r.minTime(1,3) + " hours");
System.out.println("From city 3 to 3 to city " + r.minTime(3,3) + " hours");
}
}
public class AirlineRoutesDriver
{
public static void main(String[] args)
{
int[][] routes = new int[4][4];
for (int k = 0; k < routes.length; k++)
routes[k][k] = 0;
routes[0][1] = 3;
routes[0][2] = 2;
routes[0][3] = 6;
routes[1][0] = 3;
routes[1][2] = 1;
routes[1][3] = 3;
routes[2][0] = 2;
routes[2][1] = 1;
routes[2][3] = 5;
routes[3][0] = 5;
routes[3][1] = 4;
routes[3][2] = 2;
AirlineRoutes r = new AirlineRoutes(routes);
System.out.println(r);
System.out.println("From city 4 to city 1 takes " + r.minTime(4,1) + " hours");
System.out.println("From city 1 to 3 to city " + r.minTime(1,3) + " hours");
System.out.println("From city 3 to 3 to city " + r.minTime(3,3) + " hours");
}
}
I don't know what to do for the minTime() method. I understand that I have to find the shortest time from point A to point B basically, but I don't know how to write this into code.
Thank you so much!
Update: I have found an algorithm, but I don't know how to translate it into java
Update 2: I have started writing code, I'll post it below. It's not finished yet, I need an if statement after the ctr++; statement, but I am not sure what to put in it...And then I also need to return an int in this method
public int minTime(int start, int destination)
{
int ctr = 1;
int ran = routes.length;
int shortest = 0; //keeps track of the shortest time
int longest = 0; //keeps track of the longest time
int[][] otherArray = new int[routes.length][routes[ran].length]; //creates a new array to store the shortest time in
for (int i = 0; i < routes.length; i++)
{
for (int j = 0; j < routes[i].length; j++)
{
otherArray[ctr] = otherArray[i][j+ctr] + otherArray[j+ctr][j];
ctr++;
}
}
//return some integer here!
}

You will have to use dynamic programming.
Algorithm:
Starting at A, calculate all possible paths to B. Select the shortest.

Related

Why does my method increment seemingly automatically?

I have been working through 'Head First Java', and spent an inordinate amount of time on what was seemingly a fairly simple question. And yet, could not for the life of me figure out why the method maybeNew seemingly randomly increments. I spent a good amount of time assuming it was dead code.
Does return 1 also operate as an index increaser in this case?
The code output is 14 1.
The question in the book was to work out what different flow control examples would output given the following code: e.g. having x < 19, and index < 1, for instance. Hence my confusion, given the code:
count = count + m4a[x].maybeNew(x);
Thank you for your patience.
public class Mix4 {
int counter = 0;
public static void main(String[] args) {
int count = 0;
Mix4[] m4a = new Mix4[20];
int x = 0;
while (x < 9) {
m4a[x] = new Mix4();
m4a[x].counter = m4a[x].counter + 1;
count = count + 1;
count = count + m4a[x].maybeNew(x);
x = x + 1; // 1;, 2;
}
System.out.println(count + " " + m4a[1].counter);
}
public int maybeNew(int index) { // index = 0;
if (index < 5) {
Mix4 m4 = new Mix4(); // m4 0 - 4; rn = 1;
m4.counter = m4.counter + 1; // 1.
// System.out.println(index);
return 1;
}
return 0;
}
}
If that may help:
public int maybeNew(int index) { // index = 0;
if (index < 5) {
Mix4 m4 = new Mix4(); // m4 0 - 4; rn = 1;
m4.counter = m4.counter + 1; // 1.
// System.out.println(index);
return 1;
}
return 0;
}
The whole new Mix4() is useless here: that's a dead variable because you don't really do anything with m4.
So maybeNew can be written as:
public int maybeNew(int index) { // index = 0;
if (index < 5) {
return 1;
}
return 0;
}
The whole maybeNew method could also be static (independent of any instance of Mix4):
int count = 0;
Mix4[] m4a = new Mix4[20];
int x = 0;
while (x < 9) {
m4a[x] = new Mix4();
m4a[x].counter = m4a[x].counter + 1;
count = count + 1;
count = count + Mix4.maybeNew(x);
x = x + 1; // 1;, 2;
}
System.out.println(count + " " + m4a[1].counter);
Since the code only ever use m4a[1], the other index are not used; you can move the new Mix4 and further: simplify the loop:
int count = 0;
Mix4[] m4a = new Mix4[20];
m4a[1] = new Mix4();
m4a[1].counter = m4a[1].counter + 1;
int x = 0;
while (x < 9) {
count = count + 1 + Mix4.maybeNew(x);
x = x + 1; // 1;, 2;
}
System.out.println(count + " " + m4a[1].counter);
And finally, remove the array:
int count = 0;
Mix4 m4a = new Mix4();
m4a.counter = m4a.counter + 1;
int x = 0;
while (x < 9) {
count = count + 1 + Mix4.maybeNew(x);
x = x + 1; // 1;, 2;
}
System.out.println(count + " " + m4a.counter);
The loop can then be read:
add one to count 9 times
add result of maybeNew(x):
maybeNew(0) : 1
maybeNew(1) : 1
maybeNew(2) : 1
maybeNew(3) : 1
maybeNew(4) : 1
maybeNew(5) : 0
maybeNew(6) : 0
maybeNew(7) : 0
maybeNew(8) : 0
add 5 to count
= count = 14.

Wheel of fortune statistical simulation java

The task is to simulate a wheel of fortune, which you are allowed to turn ten times.
You can spin as many times as you like, but as soon as the 0 comes, all points are gone. The program should stop the round as soon as a score over 10 is reached or a 0 comes. The results should be added at the end.
We are now at the point where the points are added and fields are fixed, but we can't think of anything to do with stopping or adding the results.
Does anyone have an idea?
Thanks in advance!
import java.util.Map;
import java.util.LinkedHashMap;
public class RandomBeispielzwei {
private static final Map<Double, Integer> GRENZEN = new LinkedHashMap<Double, Integer>();
static {
GRENZEN.put(0.1, 1);
GRENZEN.put(0.2, 2);
GRENZEN.put(0.3, 3);
GRENZEN.put(0.4, 1);
GRENZEN.put(0.5, 2);
GRENZEN.put(0.6, 3);
GRENZEN.put(0.7, 1);
GRENZEN.put(0.8, 2);
GRENZEN.put(0.9, 3);
GRENZEN.put(1.0, 0);
}
private Integer naechsteZufallzahl() {
double random = Math.random();
for (Map.Entry<Double, Integer> entry : GRENZEN.entrySet()) {
if (random <= entry.getKey().doubleValue()) {
return entry.getValue();
}
}
throw new UnsupportedOperationException("Fuer die Zufallszahl wurde kein passender Wert in der Map gefunden");
}
public static void main(String[] args) {
int anzahl1 = 0;
int anzahl2 = 0;
int anzahl3 = 0;
int anzahl0 = 0;
RandomBeispielzwei b = new RandomBeispielzwei();
for (int i = 0; i < 10; i++) {
Integer z = b.naechsteZufallzahl();
if (z.intValue() == 1) {
anzahl1++;
} else if (z.intValue() == 2) {
anzahl2++;
} else if (z.intValue() == 3) {
anzahl3++;
} else {
anzahl0++;
}
}
int ges1 = anzahl1 * 1;
int ges2 = anzahl1 * 2;
int ges3 = anzahl1 * 3;
System.out.println("1: " + anzahl1);
System.out.println("Punktzahl 1: " + ges1);
System.out.println("2: " + anzahl2);
System.out.println("Punktzahl 2: " + ges2);
System.out.println("3: " + anzahl3);
System.out.println("Punktzahl 3: " + ges3);
System.out.println("0: " + anzahl0);
System.out.println("Gesamtzahl: " + (anzahl1 + anzahl2 + anzahl3 + anzahl0));
System.out.println("Gesamtpunktzahl: " + (ges1 + ges2 + ges3));
}
}
For exiting the for-loop (and any other loop), you can use the "break" statement, which simply ends the loop (similar to how "return" will exit a method). In order to be able to stop once the total score reaches ten, you of course need to keep track of the total score. To do this, the easiest way would be to introduce aa integer variable (e.g. "gesamtpunktzahl"), to which you add the amount of points scored in each turn. In all, it would look something like this:
import java.util.Map;
import java.util.LinkedHashMap;
public class RandomBeispielZwei {
private static final Map<Double, Integer> GRENZEN = new LinkedHashMap<Double, Integer>();
static {
GRENZEN.put(0.1, 1);
GRENZEN.put(0.2, 2);
GRENZEN.put(0.3, 3);
GRENZEN.put(0.4, 1);
GRENZEN.put(0.5, 2);
GRENZEN.put(0.6, 3);
GRENZEN.put(0.7, 1);
GRENZEN.put(0.8, 2);
GRENZEN.put(0.9, 3);
GRENZEN.put(1.0, 0);
}
private Integer naechsteZufallzahl() {
double random = Math.random();
for (Map.Entry<Double, Integer> entry : GRENZEN.entrySet()) {
if (random <= entry.getKey().doubleValue()) {
return entry.getValue();
}
}
throw new UnsupportedOperationException("Fuer die Zufallszahl wurde kein passender Wert in der Map gefunden");
}
public static void main(String[] args) {
int anzahl1 = 0;
int anzahl2 = 0;
int anzahl3 = 0;
int anzahl0 = 0;
int gesamtpunktzahl = 0; // this will store what the total score is so far
RandomBeispielzwei b = new RandomBeispielzwei();
for (int i = 0; i < 10000; i++) {
Integer z = b.naechsteZufallzahl();
if (z.intValue() == 1) {
anzahl1++;
gesamtpunktzahl++; // a 1 was scored, so we increase the total score by 1
} else if (z.intValue() == 2) {
anzahl2++;
gesamtpunktzahl += 2; // same with a 2
} else if (z.intValue() == 3) {
anzahl3++;
gesamtpunktzahl += 3; // same with a 3
} else {
anzahl0++;
break; // a 0 was rolled, so we end the game (by exiting the for-loop)
}
if (gesamtpunktzahl >= 10) break; // at least 10 points were scored so far, so we exit the for-loop
}
int ges1 = anzahl1 * 1;
int ges2 = anzahl1 * 2;
int ges3 = anzahl1 * 3;
System.out.println("1: " + anzahl1);
System.out.println("Punktzahl 1: " + ges1);
System.out.println("2: " + anzahl2);
System.out.println("Punktzahl 2: " + ges2);
System.out.println("3: " + anzahl3);
System.out.println("Punktzahl 3: " + ges3);
System.out.println("0: " + anzahl0);
System.out.println("Gesamtzahl: " + (anzahl1 + anzahl2 + anzahl3 + anzahl0));
System.out.println("Gesamtpunktzahl: " + gesamtpunktzahl); // since we calculated it anyway, we might as well just use it here
}
}
I suggest using the loop do ... while for the counting and printing.
And please check you code - does you need count the same variable anzahl1 for each ges?:
int ges1 = anzahl1 * 1;
int ges2 = anzahl1 * 2;
int ges3 = anzahl1 * 3;
if not - then replace ges[i] = anzahles[1] * (i+1); to ges[i] = anzahles[i+1] * (i+1);
public static void main(String[] args) {
int[] anzahles = new int[4];
int gesamtpunktzahl = 0;
Integer z = 0;
RandomBeispielzwei b = new RandomBeispielzwei();
do {
z = b.naechsteZufallzahl();
anzahles[z]++;
gesamtpunktzahl += z;
} while (!(z == 0 || gesamtpunktzahl >= 10));
int ges[] = new int[3];
for (int i = 0; i < 3; i++) {
ges[i] = anzahles[1] * (i+1);
System.out.println((i+1) + ": " + anzahles[i+1]);
System.out.println("Punktzahl " + (i+1) + ": " + ges[i]);
}
System.out.println("0: " + anzahles[0]);
System.out.println("Gesamtzahl: " + Arrays.stream(anzahles).sum());
System.out.println("Gesamtpunktzahl: " + Arrays.stream(ges).sum());
}

Java: How to add variable in a loop together, multiple times

public class R {
public static void main(String[] args) {
int n = Integer.parseInt(args[0]);
int trials = Integer.parseInt(args[1]);
int x = 0;
int y = 0;
int j = 0;
int distance = 0;
while (trials>j) {
j = j + 1;
int i = -1;
double counter = 1.0 * distance;
double sum = (distance + counter);
while (i<=n) {
i = i + 1;
if (i == n) {
distance = ((x*x) + (y*y));
}
if (i<n) {
int random = (int )(Math.random() * 4 + 1);
if (random == 1) x = x + 1;
if (random == 2) y = y + 1;
if (random == 3) x = x - 1;
if (random == 4) y = y - 1;
}
}
}
double average= (sum)/(trials);
System.out.println("mean " + "squared " + "distance " + "= " + average);
}
}
Hey guys I'm wondering how it's possible to compute a value within a loop, and then every single time the loop finishes (and the value in computed) to average them together. I can't wrap my head around the concept and I tried doing it in the code above but I can't quite figure it out.
As you can see there are two while loops, and inside one of them a random value (distance) is computed. So essentially I need to average the distances together, but I can't imagine how it's possible to add the distances that are computed each time together into one number. Let's say the loop goes through one time and outputs a singular distance, how would I go about adding a new distance (for the new loop) together with the old one, and then keep doing that for each trial?
You just have to divide the total distance per trials.
public class R {
public static void main(String[] args) {
int n = Integer.parseInt(args[0]);
int trials = Integer.parseInt(args[1]);
int x = 0;
int y = 0;
int j = 0;
int distance = 0, distance_total = 0;
while (trials>j) {
j = j + 1;
int i = -1;
distance = 0;
while (i<=n) {
i = i + 1;
if (i == n) {
distance += ((x*x) + (y*y));
}
if (i<n) {
int random = (int )(Math.random() * 4 + 1);
if (random == 1) x = x + 1;
if (random == 2) y = y + 1;
if (random == 3) x = x - 1;
if (random == 4) y = y - 1;
}
}
distance_total += distance;
}
System.out.println(distance_total/j);
}
}

How can I optimize my java implementation of Held-Karp algorithm to shorten the running time?

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

divide bags of candies among three children evenly

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.

Categories