Elementary Java Algorithm Assistance - java

I need help writing a program that is given a specified number of coordinate points in the form (X,Y). The number of points that will be given is the first line in the program; it can be read in through a scanner.
I need to calculate the least amount of area to cover all of the points with the lines x = a, and y = b. So, the area would be a * b (Area of a rectangle).
However, one coordinate point (X, Y) must be removed to optimize the area. The point that is removed should minimize the area as much as possible. I need help writing algorithm to do so.
This is a sample input, and output that I was given ::
SAMPLE INPUT
4
2 4
1 1
5 2
17 25
SAMPLE OUTPUT
12
In this example, the first line of input (4) indicates that four points will be input. The next four lines are the coordinates in form (x, y). The last point which is (17, 25) is removed as the outlier which leaves us with the first three points.
If the three remaining points are graphed, they can all be inside a box (3 by 4) hence the output is 12; (3 * 4). It is OK for the line to be on the point like in this example. However, the outlier is not always the last point, or very big. The outlier could be very small, the area just needs to be minimized.
--
This is what I have so far (I know it's not very much..) - please help me!
It's mostly just the algorithm that I need help with..
import java.io.*;
import java.util.*;
public class Area {
public static void main(String args[]) {
Scanner scan = new Scanner(System.in);
int numOfPoints = scan.nextInt();
int Xcoordinates[] = new int[numOfPoints];
int Ycoordinates[] = new int[numOfPoints];
for (int i = 0; i <= numOfCows - 1; i++) {
Xcoordinates[i] = scan.nextInt();
Ycoordinates[i] = scan.nextInt();
}
}
}
Possible Pseudocode (continuing from above; this may be wrong..):
for (int i = 0; i <= Xcoordinates.length; i++) { //loop through array
compare values, and determine outlier
int lowestXValue = [find lowest x value]
int highestXValue = [find highest x value; not outlier] }
remove xcoordinates[outlier]
remove ycoordinates[outlier]
int xLength = highestXValue - lowestXValue - 1 // -1 because can be on line
for (int i = 0; i <= Ycoordinates.length; i++) { //loop through y array
int lowestYValue = [find lowest y value]
int highestYValue = [find highesy Y value] }
int yLength = highestYValue - lowestYValue - 1;
int boxArea = yLength * xLength
System.out.println(boxArea);
However, this would only search through the possible X outlier, and if there's a Y value that would minimize area by removal, it would not catch that

I would create two sorted lists of integers, one for the x co-ords and one for the y co-ords. Then you can check the area saved by removing the max x co-ordinate (area saved should be max y co-ordinate times (max x co-ordinate - second highest x co-ordinate)). You can do the same thing to check the area saved by removing the max y co-ordinate, and whichever is greater will be your final answer.

Related

Why doesn't my code flip image horizontally?

public void flipImageHorizontally(){
this.redisplayImage();
for(int x = 0; x < this.image.length; x++)
for(int y = 0; y < this.image[0].length; y++){
this.image[x][y] = this.image[x][this.image[0].length - 1 - y];
}
}
The code runs but it doesn't perform the action intended. It is supposed to flip the image horizontally, but instead it only flips half of the image.
Let's say you have an image two pixels wide and one pixel high:
1 2
After the first iteration of your loop, the end pixel will be swapped to the beginning (image[0][0] = image[0][2 - 1 - 0];):
2 2
But now you lost the original value of image[0][0]! So when you do the swap image[0][1] = image[0][2 - 1 - 1];, you are copying the second half of the image back to itself.
The right answer is to use a buffer so you don't overwrite the swap:
for(int y = 0; y < this.image[0].length / 2; y++) {
int buffer = this.image[x][y];
this.image[x][y] = this.image[x][this.image[0].length - 1 - y];
this.image[x][this.image[0].length - 1 - y] = buffer;
}
Integer truncation ensures that this.image[0].length / 2 is an efficient bound. For even numbers, you iterate exactly the first half. For odd numbers, you iterate the first half, not including the middle pixel. That's a good thing, because the middle does not need to be swapped.
You need to iterate up to the middle, and swap pixels that are on the left with pixels that are on the right. Otherwise you end up overwriting your changes.
public void flipImageHorizontally() {
this.redisplayImage();
for(int x = 0; x < this.image.length; x++) {
for(int y = 0; y < this.image[x].length / 2; y++) {
int pixel = this.image[x][y]; // assuming int
this.image[x][y] = this.image[x][this.image[x].length - 1 - y];
this.image[x][this.image[x].length - 1 - y] = pixel;
}
}
}
In this code
the pixel variable temporarily holds the value on the left;
the value on the left gets assigned the value on the right;
the value on the right gets the value that was originally on the left (i.e. whatever is in pixel).
Notes:
I maintained your naming of x and y, even though it's counter-intuitive because it makes it look like you're performing a vertical flip instead of a horizontal one.
I don't know the data type of the array; I assumed int, but it might be a float array, Pixel objects, or something else.
I don't know what this.redisplayImage(); is supposed to do, and whether it's in the right location.

I don't understand what the multiplication in q.offer(x*m + y) does and what the while loop is doing and everything in the code

Can someone explain this code in detail, I don't understand what the multiplication in q.offer(x*m + y) does and what the while loop is doing. This is the requirements for the program:
Starting from a given location on the grid, experiment explores the grid, expanding and labeling all of the cells in a single colony originating from the starting location. Taking as input a grid, the coordinates of a starting location, and a label, experiment will either label that location and all its neighbors or do nothing, depending on the presence or absence of a cell at the given location, respectively; either way, experiment is required to return the size of the labeled colony.
(c) The program is responsible for ensuring that experiment is called start- ing at every location on the grid storing a 1. The reason is that experiment locates only a single colony.
For example, using the first grid above and calling experiment for the first time on the location at the top row and forth column will modify the grid only at the locations labeled A, leaving all the other locations intact.
Once every grid location storing a 1 has been colonized, the program freezes the grid by replacing the 0s on the grid with s (dashes) .
(d) The program is responsible for creating an initial grid of random number of rows and columns in the range [5-20], and for filling the grid randomly with 0s and 1s.
(e) The program is responsible for generating the labels for experiment to use during exploration. Use the alphabet letters A · · · Z and a · · · z as labels (in that order).
public static Map<Character, Integer> experiment(int n, int m, int x, int y, char[][] matrix, int[][] mark, char colony) {
Queue<Integer> q = new LinkedList<Integer>();
q.offer(x*m + y);
mark[x][y] = 1;
matrix[x][y] = colony;
while(!q.isEmpty()) {
int front = q.peek(); q.remove();
int x1 = front / m, y1 = front % m;
if(x1 != 0)
if(mark[x1-1][y1] == 0 && matrix[x1-1][y1] == '1') {
matrix[x1-1][y1] = colony;
mark[x1-1][y1] = 1;
q.offer((x1-1) * m + y1);
}
I just don't understand this part of code. Can someone please explain it.
one possible explanation could be that
x and y are coordinates of grid,
if you loop over x and y as below
for( int x = 0 ; x < width; x++ ){
for( int y = 0 ; y < height; y++ ){
index_of_one_dimensional_array = x*m+y;//where m = width(i.e number if columns in each row)
}
}
seems like the q.offer() functions somehow uses this concept to set a value depending on value of index_of_one_dimensional_array given by x*m+y;
and loop is used to make sure every cell in the grid is processed which happens when the queue is empty

Sieve of Eratosthenes Issue Java

I've got an issue with an assignment that I have requiring the use of arrays. I need to create the Sieve of Eratosthenes algorithm and print out all the prime numbers. I'm quite confused because as far as I can tell, my order of operations is correct. Here is the code:
//Declare the array
boolean numbers [] = new boolean[1000];
int y = 0;
//Declare all numbers as true to begin
for(int i = 2; i < 1000;i++){
numbers[i] = true;
}
//Run loop that increases i and multiplies it by increasing multiples
for (int x = 2; x < 1000; x++) {
//A loop for the increasing multiples; keep those numbers below 1000
//Set any multiple of "x" to false
for(int n = 2; y < 1000; n++){
y = n * x;
numbers[y] = false;
}
}
I first set all the numbers in the array to true. Then the second loop will start "x" at 2, then inside it is a nested loop that will multiply "x" by values of "n" and "n" will continue to increase as long as the product of that multiplication ("y") is below 1000. Once "y" reaches that maximum, "x" will go up one number and the process repeats until all non-prime numbers are set to false.
That was my logic when I made the code, but when I try to run it I get the "ArrayIndexOutOfBoundsException" error. From what I can tell I set everything to stay below 1000 so it shouldn't be going over the array size.
I know its probably not the most efficient algorithm because as "x" increases it will go over numbers it already went over but it was the most simple one I could think of.
Here:
for(int n = 2; y < 1000; n++){
y = n * x;
numbers[y] = false;
}
you first check that y < 1000, and then intialize and use it. This is the wrong way around.
Also, you can get away with running the above loop only when x is prime. This won't affect correctness, but should make your code much faster.

Perlin Noise function returning same results for different inputs

I am using a perlin noise function to generate data for a game I am making, but for some reason it keeps returning the exact same results for different inputs. I spent like 4 hours trying to debug this on my FBM function and couldn't figure it out so I tried Ken Perlin's improved noise function and the same thing happens.
Does anyone know why this is? What is a good way to fix it? The only thing I have been able to do is add a decimal value like .6473 to the x and y coordinates, which helped, but introduced other problems such as the values repeating themselves inside the arrays.
Here is some test code. I am trying to create two different 2D arrays filled with noise values. The x and y inputs are coordinates from my game. On the lines with '**' after them, if I don't increase those values, both arrays will be filled with all zeros. In the example, the coordinates (0.0, -768.0) and (-1024.0, -768.0) return the exact same noise values. In my game, 9 different coordinates return the same values.
The Perlin Noise function I am using for this test is here
public class TestPerlinMain
{
public static void main(String[] args)
{
int seed = 532434;
//create first noise array
double x = 0.0; //x-coordinate
double y = -768.0; //y-coordinate
float z = 10.0f;
double[][] test = new double[15][15];
System.out.println("Noise Array 1: ");
for(int i = 0; i < test.length; i++)
{
for(int j = 0; j < test[i].length; j++)
{
test[i][j] = ImprovedNoise.noise(x + (j * 64.0), y + (i * 64.0), 10.0);
x += .314f;//************
System.out.print(test[i][j] + " ");
}
y += .314f;//***********
}
System.out.println();
//create 2nd noise array
double x2 = -1024.0; //x coordinate
double y2 = -768.0; //y coordinate
float z2 = 10.0f;
System.out.println();
double[][] test2 = new double[15][15];
System.out.println("Noise Array 2: ");
for(int i = 0; i < test2.length; i++)
{
for(int j = 0; j < test2[i].length; j++)
{
test2[i][j] = ImprovedNoise.noise(x2 + (j * 64.0), y2 + (i * 64.0), 10.0);
x2 += .314f;//*************
System.out.print(test2[i][j] + " ");
}
y2 += .314f;//************
}
System.out.println();
}
Perlin noise is defined to be 0 at all grid locations (integer x, y, z). You can prove this to yourself by hand-simulating it in the code you linked. Since x, y, and z all become 0 when their floors are subtracted, the grad() values are all 0, so the lerp() values are all 0.
There are several ways to get the noise you want. First, if you use a non-integer value of z, then you should get random values of noise. However, since your grid spacing of 64 is much larger than the noise basis, this will look like static, not Perlin noise. A better approach would be to scale up the noise by doing something like noise(j/4., i/4., z). Sampling 4 points across each noise cell will allow some of the smoothness of the noise to be seen.
Note also that your noise implementation is designed to repeat with tiles of size 256 in each direction (see the first line of noise(). This is why you get repeating values every 4 in your array.

Java: random integer with non-uniform distribution

How can I create a random integer n in Java, between 1 and k with a "linear descending distribution", i.e. 1 is most likely, 2 is less likely, 3 less likely, ..., k least likely, and the probabilities descend linearly, like this:
I know that there are dozens of threads on this topic already, and I apologize for making a new one, but I can't seem to be able to create what I need from them. I know that using import java.util.*;, the code
Random r=new Random();
int n=r.nextInt(k)+1;
creates a random integer between 1 and k, distributed uniformly.
GENERALIZATION: Any hints for creating an arbitrarily distributed integer, i.e. f(n)=some function, P(n)=f(n)/(f(1)+...+f(k))), would also be appreciated, for example:
.
This should give you what you need:
public static int getLinnearRandomNumber(int maxSize){
//Get a linearly multiplied random number
int randomMultiplier = maxSize * (maxSize + 1) / 2;
Random r=new Random();
int randomInt = r.nextInt(randomMultiplier);
//Linearly iterate through the possible values to find the correct one
int linearRandomNumber = 0;
for(int i=maxSize; randomInt >= 0; i--){
randomInt -= i;
linearRandomNumber++;
}
return linearRandomNumber;
}
Also, here is a general solution for POSITIVE functions (negative functions don't really make sense) along the range from start index to stopIndex:
public static int getYourPositiveFunctionRandomNumber(int startIndex, int stopIndex) {
//Generate a random number whose value ranges from 0.0 to the sum of the values of yourFunction for all the possible integer return values from startIndex to stopIndex.
double randomMultiplier = 0;
for (int i = startIndex; i <= stopIndex; i++) {
randomMultiplier += yourFunction(i);//yourFunction(startIndex) + yourFunction(startIndex + 1) + .. yourFunction(stopIndex -1) + yourFunction(stopIndex)
}
Random r = new Random();
double randomDouble = r.nextDouble() * randomMultiplier;
//For each possible integer return value, subtract yourFunction value for that possible return value till you get below 0. Once you get below 0, return the current value.
int yourFunctionRandomNumber = startIndex;
randomDouble = randomDouble - yourFunction(yourFunctionRandomNumber);
while (randomDouble >= 0) {
yourFunctionRandomNumber++;
randomDouble = randomDouble - yourFunction(yourFunctionRandomNumber);
}
return yourFunctionRandomNumber;
}
Note: For functions that may return negative values, one method could be to take the absolute value of that function and apply it to the above solution for each yourFunction call.
So we need the following distribution, from least likely to most likely:
*
**
***
****
*****
etc.
Lets try mapping a uniformly distributed integer random variable to that distribution:
1
2 3
4 5 6
7 8 9 10
11 12 13 14 15
etc.
This way, if we generate a uniformly distributed random integer from 1 to, say, 15 in this case for K = 5, we just need to figure out which bucket it fits it. The tricky part is how to do this.
Note that the numbers on the right are the triangular numbers! This means that for randomly-generated X from 1 to T_n, we just need to find N such that T_(n-1) < X <= T_n. Fortunately there is a well-defined formula to find the 'triangular root' of a given number, which we can use as the core of our mapping from uniform distribution to bucket:
// Assume k is given, via parameter or otherwise
int k;
// Assume also that r has already been initialized as a valid Random instance
Random r = new Random();
// First, generate a number from 1 to T_k
int triangularK = k * (k + 1) / 2;
int x = r.nextInt(triangularK) + 1;
// Next, figure out which bucket x fits into, bounded by
// triangular numbers by taking the triangular root
// We're dealing strictly with positive integers, so we can
// safely ignore the - part of the +/- in the triangular root equation
double triangularRoot = (Math.sqrt(8 * x + 1) - 1) / 2;
int bucket = (int) Math.ceil(triangularRoot);
// Buckets start at 1 as the least likely; we want k to be the least likely
int n = k - bucket + 1;
n should now have the specified distribution.
Let me try another answer too, inspired by rlibby. This particular distribution is also the distribution of the smaller of two values chosen uniformly and random from the same range.
There are lots of ways to do this, but probably the easiest is just to generate
two random integers, one between 0 and k, call it x, one between 0 and h, call it y. If y > mx + b (m and b chosen appropriately...) then
k-x, else x.
Edit: responding to comments up here so I can have a little more space.
Basically my solution exploits symmetry in your original distribution, where p(x) is a linear function of x. I responded before your edit about generalization, and this solution doesn't work in the general case (because there is no such symmetry in the general case).
I imagined the problem like this:
You have two right triangles, each k x h, with a common hypotenuse. The composite shape is a k x h rectangle.
Generate a random point that falls on each point within the rectangle with equal probability.
Half the time it will fall in one triangle, half the time in the other.
Suppose the point falls in the lower triangle.
The triangle basically describes the P.M.F., and the "height" of the triangle over each x-value describes the probability that the point will have such an x-value. (Remember that we're only dealing with points in the lower triangle.) So by yield the x-value.
Suppose the point falls in the upper triangle.
Invert the coordinates and handle it as above with the lower triangle.
You'll have to take care of the edge cases also (I didn't bother). E.g. I see now that your distribution starts at 1, not 0, so there's an off-by-one in there, but it's easily fixed.
There is no need to simulate this with arrays and such, if your distribution is such that you can compute its cumulative distribution function (cdf). Above you have a probability distribution function (pdf). h is actually determined, since the area under the curve must be 1. For simplicity of math, let me also assume you're picking a number in [0,k).
The pdf here is f(x) = (2/k) * (1 - x/k), if I read you right. The cdf is just integral of the pdf. Here, that's F(x) = (2/k) * (x - x^2 / 2k). (You can repeat this logic for any pdf function if it's integrable.)
Then you need to compute the inverse of the cdf function, F^-1(x) and if I weren't lazy, I'd do it for you.
But the good news is this: once you have F^-1(x), all you do is apply it to a random value distribution uniformly in [0,1] and apply the function to it. java.util.Random can provide that with some care. That's your randomly sampled value from your distribution.
This is called a triangular distribution, although yours is a degenerate case with the mode equal to the minimum value. Wikipedia has equations for how to create one given a uniformly distributed (0,1) variable.
The first solution that comes to mind is to use a blocked-array. Each index would specify a range of values depending on how "probable" you want it to be. In this case, you would use a wider range for 1, less wider for 2, and so on until you reach a small value (lets say 1) for k.
int [] indexBound = new int[k];
int prevBound =0;
for(int i=0;i<k;i++){
indexBound[i] = prevBound+prob(i);
prevBound=indexBound[i];
}
int r = new Random().nextInt(prevBound);
for(int i=0;i<k;i++){
if(r > indexBound[i];
return i;
}
Now the problem is just finding a random number, and then mapping that number to its bucket.
you can do this for any distribution provided you can discretize the width of each interval.
Let me know if i am missing something either in explaining the algorithm or its correctness. Needless to say, this needs to be optimized.
Something like this....
class DiscreteDistribution
{
// cumulative distribution
final private double[] cdf;
final private int k;
public DiscreteDistribution(Function<Integer, Double> pdf, int k)
{
this.k = k;
this.cdf = new double[k];
double S = 0;
for (int i = 0; i < k; ++i)
{
double p = pdf.apply(i+1);
S += p;
this.cdf[i] = S;
}
for (int i = 0; i < k; ++i)
{
this.cdf[i] /= S;
}
}
/**
* transform a cumulative distribution between 0 (inclusive) and 1 (exclusive)
* to an integer between 1 and k.
*/
public int transform(double q)
{
// exercise for the reader:
// binary search on cdf for the lowest index i where q < cdf[i]
// return this number + 1 (to get into a 1-based index.
// If q >= 1, return k.
}
}
The Cumulative Distribution Function is x^2 for a triangular distribution [0,1] with mode (highest weighted probability) of 1, as shown here.
Therefore, all we need to do to transform a uniform distribution (such as Java's Random::nextDouble) into a convenient triangular distribution weighted towards 1 is: simply take the square root Math.sqrt(rand.nextDouble()), which can then multiplied by any desired range.
For your example:
int a = 1; // lower bound, inclusive
int b = k; // upper bound, exclusive
double weightedRand = Math.sqrt(rand.nextDouble()); // use triangular distribution
weightedRand = 1.0 - weightedRand; // invert the distribution (greater density at bottom)
int result = (int) Math.floor((b-a) * weightedRand);
result += a; // offset by lower bound
if(result >= b) result = a; // handle the edge case
The simplest thing to do it to generate a list or array of all the possible values in their weights.
int k = /* possible values */
int[] results = new int[k*(k+1)/2];
for(int i=1,r=0;i<=k;i++)
for(int j=0;j<=k-i;j++)
results[r++] = i;
// k=4 => { 1,1,1,1,2,2,2,3,3,4 }
// to get a value with a given distribution.
int n = results[random.nextInt(results.length)];
This best works for relatively small k values.ie. k < 1000. ;)
For larger numbers you can use a bucket approach
int k =
int[] buckets = new int[k+1];
for(int i=1;i<k;i++)
buckets[i] = buckets[i-1] + k - i + 1;
int r = random.nextInt(buckets[buckets.length-1]);
int n = Arrays.binarySearch(buckets, r);
n = n < 0 ? -n : n + 1;
The cost of the binary search is fairly small but not as efficient as a direct look up (for a small array)
For an arbitary distrubution you can use a double[] for the cumlative distrubution and use a binary search to find the value.

Categories

Resources