Stacking Tiles (Hard algorithm) - java

This is a question from a code competition, I am finding it unbelievably difficult to come up with any working algorithm to solve it. So I'm not really looking for the code but rather a step by step algorithm on how to solve it.
Stacking Tiles
Stacking tiles against the wall is one of Bongani's favourite pasttimes. His tiles all have the same thickness, but vary
in width and height. Bongani is given N tiles and has to use them in
the sequence given according to a set of rules. He can place a tile on
top of another only if it is narrower than the previously stacked
tile. Bongani is allowed to rotate the tiles by 90 degrees so that
width becomes height and height becomes width. He is also allowed to
discard a tile altogether. Given a list of tiles, help Bongani find
the highest stack he can build The example specifies tiles (3, 3),
(12, 5), (5, 8), (6, 10). To get the highest stack Bongani ignores the
first tile (3, 3) as it is smaller than the next tile. He uses the
next tile (12, 5) with 12 as the width and 5 as the height. He uses
the next two tiles with 8 as the width and 5 as the height followed by
6 as the width and 10 as the height.
The only thing I can possibly think of is getting every possible valid permutation of tiles and find the highest permutation.
The exact question can be found here http://www.olympiad.org.za/olympiad/wp-content/uploads/2013/01/2011PO-R2-Questions-0421.pdf (Question 5)

Here's an outline of dynamic programming solution:
You "move from left to right" and for each tile you figure out
how high tower can I build by using this tile unrotated
how high tower can I build by using this tile rotated
how high tower can I build by not using this tile
The first key observation is that each question can be answered recursively ("how high tower can I build for the remaining tiles if the current width is updated according to my current choice?"). Pseudo code:
maxHeight(tiles, currentWidth) {
// Base case
if (tiles.isEmpty())
return 0; // no tiles -> maxHeight == 0
int h = 0;
currentTile = tiles[0]
remainingTiles = tiles[1...]
// Compute maxHeight for the case when not using current tile
h = max(h, maxHeight(remainingTiles, currentWidth)
// Compute maxHeight when using current tile
if (currentWidth > currentTile.width)
subHeight = maxHeight(remainingTiles, currentTile.width)
h = max(h, subHeight + currentTile.height)
// Compute maxHeight when using current tile rotated
if (currentWidth > currentTile.height)
subHeight = maxHeight(remainingTiles, currentTile.height)
h = max(h, subHeight + currentTile.width)
return h
}
The second key observation is that many of the invocations of maxHeight have the same arguments, which means that previous computations can be reused. You can either use memoization or tabulation (both are variants of dynamic programming) If you choose to use a tabulation matrix, it would look like this:
M[tileN][width] = the height of the tower possible to build from
tileN onwards with width 'width'
(As you may note width does not have a clear upper bound. This can be solved by mapping all values to 1, 2, 3, ... before starting. Maximum width will then be 2N.)

Here is a quadratic time algorithm using dynamic programming. Let f(i) be the greatest height of a tower you can build using the ith block in the original orientation and no later blocks. Let g(i) be the greatest height of a tower you can build with the ith block rotated and no later blocks. Note that blocks can be omitted, so to compute f(i), you have to take 1 more than the maximum over all previous f and g values compatible with that orientation, and similarly for g(i). At the end, the answer is the maximum over all f(i) and g(i).
The following code shows code for f. Youc an write g similarly, or modify this to take another parameter for whether block i is in the original orientation.
public int f(int i)
{
if (i == 0)
return 1;
if (memoF[i] > 0)
return memoF[i];
int maxFound = 1; // using just this block is legal
for (int j = 0; j<i; j++){
if (widths[i] < widths[j])
maxFound = Math.max(f(j)+1,maxFound);
if (widths[i] < heights[j])
maxFound = Math.max(g(j)+1,maxFound);
}
memoF[i] = maxFound;
return memoF[i];
}

I think this is typical example for easy and effective solving using Backtracking.
You just go in sequence and try first things you can do, when you cant continue, you go back and try the one you did not try before. Just google "Sudoku Backtracking" there are a lot of pages explaing that.
The huge advantage of backtracking in this case is, it "cuts" off a lot scenariou which would make no sense, therefore it would be much more effective than trying to check every possible combination.
(like in sudoku, with backtracking, the most sudokus are solved in 1000-10000 steps, which is pretty good, given that the all possible combinations of numbers you can write are ~10^60)

Related

Fastest way to check which rectangle is clicked in a list of rectangles

I have a rectangle Object with x, y, width and height. I have a list of these rectangles which are displayed on a screen. It is guaranteed that none of them overlap. Given a user's click position (x and y coordinates), I want to see which of these rectangles were clicked (since they do not overlap, there is a maximum of one rect that can be clicked).
I can obviously look through all of them and check for each one if the user clicked it but this is very slow because there are many on the screen. I can use some kind of comparison to keep the rectangles sorted when I insert a new one into the list. Is there some way to use something similar to binary search in order to decrease the time it takes to find which rect was clicked?
Note: the rectangles can be any size.
Thanks:)
Edit: To get an idea of what I am making visit koalastothemax.com
It highly depends upon your application and details we're not quite aware of yet for what the best solution would be. BUT, with as little as I know, I'd say you can make a 2D array that points to your rectangles. That 2D array would map directly to the pixels on the screen. So if you make the array 10x20, then the coordinate x divided by screen width times 10 (casted to int) will be the first index and y divided screen height times 20 would be your y index. With your x and y index, you can map directly to the rectangle that it points to. Some indexes might be empty and some might point to more than one rectangle if they're not perfectly laid out, but that seems the easiest way to me without knowing much about the application.
I have tackled a very similar problem in the past when developing a simulation. In my case the coordinates were doubles (so no integer indexing was possible) and there could be hundreds of millions of them that needed to be searched.
My solution was to create an Axis class to represent each axis as a sequence of ranges. The ranges were guaranteed to go from a minimum to a maximum and the class was smart enough to split itself into pieces when new ranges were added. Each range has a single generic object stored. The class used a binary search to find a range quickly.
So roughly the class looks like:
class Axis<T> {
public Axis(double min, double max, Supplier<T> creator);
public Stream<T> add(double from, double to);
public T get(double coord);
}
The add method needs to return a stream because the added range may cover several ranges.
To store rectanges:
Axis<Axis<Rectangle>> rectanges = new Axis<>(0.0, 100.0,
() -> new Axis<>(0.0, 100.0, Rectangle::new));
rectangles.add(x, x + w).forEach(r -> r.add(y, y + h).forEach(Rectangle::setPresent));
And to find a rectangle:
rectangles.get(x).get(y);
Note that there's always an object stored so you need a representation such as Rectangle.NULL for 'not present'. Or you could make it Optional<Rectangle> (though that indirection eats a lot of memory and processing for large numbers of rectangles).
I've just given the high level design here rather than any implementation details so let me know if you want more info on how to make it work. Getting the logic right on the range splits is not trivial. But I can guarantee that it's very fast even with very large numbers of rectangles.
The fastest way I can come up with is definitely not the most memory efficient. This works by exploiting the fact that an amortized hash table has constant lookup time. It will map every point that a rectangle has to that rectangle. This is only really effective if your are using integers. You might be able to get it to work with floats if you use a bit of rounding.
Make sure that the Point class has a hash code and equals function.
public class PointCheck
{
public Map<Point, Rect> pointMap;
public PointCheck()
{
pointMap = new HashMap<>();
}
/**
* Map all points that contain the rectangle
* to the rectangle.
*/
public void addRect(Rect rect)
{
for(int i = rect.x; i < rect.x + rect.width; ++i)
{
for(int j = rect.y; j < rect.y + rect.height; ++i)
{
pointMap.put(new Point(i, j), rect);
}
}
}
/**
* Returns the rectangle clicked, null
* if there is no rectangle.
*/
public Rect checkClick(Point click)
{
return pointMap.get(click);
}
}
Edit:
Just thought I should mention this: All of the rectangles held in the value of the hash map are references to the original rectangle, they are not clones.

Noise generation: 'Room Noise'

Last weeks I was developing a world generator (for a Minecraft mod). However, I wasn't looking for just Perlin noise, but rather something based on cell noise. I want to generate a sort of underground lab, existing of several rooms of different sizes.
To explain the problem I use 2D examples.
The noise generator takes a grid cell position (int x, int y), and returns an object with this stucture:
boolean top;
boolean right;
boolean down;
boolean left;
int roomType;
The 4 booleans represent the walls which are enabled or disabled:
The roomType represents the type of the room respectively.
The final result should be something like this:
Here, the background checkerboard pattern represents the base grid, and the black lines represent the walls. This is just a simple example that could generate, but in the real case, the grid is infinite in both x and y directions.
The problem I'm getting now is that the noise generator only takes in an x and y coordinate, which is the coordinate of the grid cell it should generate. There is a seed of which I can generate more random seeds for hash functions:
long seed = 0x75fd239de48;
Random r = new Random(seed);
int seed1 = r.nextInt();
int seed2 = r.nextInt();
// etc.
I could use a hash function: Hash.hash2D(int seed, int x, int y), which returns a random double for a coordinate, according to a seed.
That will give the ability to generate information for the surrounding cells.
To easily generate larger rooms, you could set a max size for a room, and check an area for rooms that try to be larger than 1x1. If they are there, and will span to the current room, the room will be an extension of another room. However, checking if a room will extend requires a check if it isn't already extending (otherwise, unwanted room extensions appear to room bases that extend another), which runs into an infinite loop.
In my case, there is a given table of room types, their sizes and their weights. Example:
name: size [weight]
room-1: 1x1 [128]
room-2: 1x1 [128]
room-3: 2x1 [16]
room-4: 1x2 [16]
room-5: 2x2 [8]
room-6: 3x1 [4]
room-7: 1x3 [4]
There are many others, coming with sizes up to 5x5, but I use this example list for my question. The max size in this example is 3x3 (just max-width by max-height).
Here I have an example class of some basic setup in Java:
public class RoomNoise {
private final long seed;
private final Random rand;
public RoomNoise( long seed ) {
this.seed = seed;
this.rand = new Random( seed );
}
public enum RoomTypes {
ROOM1( 1, 1, 128 ),
ROOM2( 1, 1, 128 ),
ROOM3( 2, 1, 16 ),
ROOM4( 1, 2, 16 ),
ROOM5( 2, 2, 8 ),
ROOM6( 1, 3, 4 ),
ROOM7( 3, 1, 4 );
public final int width;
public final int height;
public final int weight;
private RoomTypes( int w, int h, int weight ) {
width = w;
height = h;
this.weight = weight;
}
}
public static class Output {
public final RoomTypes roomType;
public final boolean upWall;
public final boolean rightWall;
public final boolean downWall;
public final boolean leftWall;
public Output( RoomTypes type, boolean u, boolean r, boolean d, boolean l ) {
roomType = type;
upWall = u;
rightWall = r;
downWall = d;
leftWall = l;
}
}
public Output generate( int x, int y ) {
// What should be here
}
}
I'm looking for the content of the generate method, for which I've tried many things, but every time I turned into an infinite loop or it didn't work.
Is there any way to generate this noise in O(N) with N less than infinity? And if there is a way, which way is that and how could I implement it? I've searched the internet and tried many things (for 3 weeks now) and still haven't found a solution.
I use Java 1.8, but I prefer any C-style language.
Again, I have this hash function:
Hash.hash2D( int seed, int x, int y );
Edit:
Expected result:
Blue lines are corridors, which are generated later on. Just forget them.
Note:
I'm not able to load and delete chunks (grid cells) manually, the base API (Minecraft) is doing that for me. It only gives me the coordinate (which depends on the player interaction) and I should give back a (part of a) room that fits the chunk at that coordinate. I also know that once a chunk is generated, it isn't generated again.
I'm not sure I perfectly understand the problem you're trying to solve, so please feel free to comment if this is short of the mark:
If you want to be able to generate an infinite grid, you're only going to be able to approximate infinite. I think you have two options:
Generate a "big enough" grid. This might be time / space intensive, but if there's an upper bound on how much you could need, and it's feasible to do it all at once, it's the simplest option. E.g. if the user couldn't possibly make it more than 1000 squares away from the center, generate 2000x2000.
OR:
Use lazy evaluation. This means, don't generate anything until you need it. If the user gets close to an area that has not yet been generated, generate it then. The flip side to this is you can also throw away old parts that the user isn't likely to return to, if you need to free up resources. For example: cut your area into squares (e.g. 20x20 or 1000x1000), and generate additional, adjacent squares, as the player gets close to them, or the map pans over in that direction, etc., as needed.
Ok, I think I've solved it myself.
This is the grid, not infinite here but it could be.
In this grid you have some cells that want to extend. This is directly defined by the hash function:
However, some extensions do overlap others. This is something we don't know actually.
Take for each cell a priority. You could do that in several ways:
Just use the hash function to give them a random priority
Give each possible room type / size a priority (e.g. larger rooms have higher priority).
The priority is only important on cells that want to extend. In my example, the bigger cells have higher priority.
Then we have the input coordinate, which is the blue cell:
Ok, knowing this, you have to do some steps. We know the maximum size is 3x3.
If the input cell doesn't want to extend
Check in the area of the maximum size if there is any cell that tries to extend to this cell:In this case it exists.
Knowing this, we need to check if one of the found cells could extend to this cell. To check that, check if this wants this cell to be an extension, then do the steps below and take the check cell as input coordinate. In the example, the extending cell is able to extend. We also know the extending cell will extend the input cell so the input cell is an extension.
Now we could easily check which walls exist and which not. In this case, every wall is gone because it is the center of this extending room:
Some other examples:
Input coordinates. None of them wants extension:
Check regions:
As you can see, one cell found an extension room, but that extension room doesn't extend that input cell. That makes all those rooms a 1x1 room:
If the input cell wants to extend
And how to check if a cell can extend
Do a hard check. The hard check checks the area of the extension (3x3 in this case) size right below the input cell for other cells trying to extend. If there is one, check if that one could extend. If it could, the input cell couldn't extend and go on with the steps for non-extending cells on your input cell. To save memory and time, you could skip checking if the found cells could extend (maybe this will run into an infinite loop), and just take an 1x1 cell directly (non-extending cell steps are not necessary then).
This is the extension area / hard check area in this case. There is no extending cell here so the cell could extend.
Now do a soft check. The soft check checks for extending cells in the maximum size area left below, and right above the cell:
Also here, you could check if they do extend, but that takes much memory and time.
For each found cell, check in their extension area right below them if they will extend to any of the extension cells the input cell will extend. This check if the two extension areas overlap. If they don't, your cell is able to extend and you could skip step 3 and go to step 4. If they do, go to step 3. In this case an overlap is found:
Here, the yellow cell with red outline is a found overlap.
You've found an overlap. Here the priority is going to play a role. Take the priority of the extension cell which area does overlap the input cell area. Also take the priority of the input cell itself. Compare them. If the priority of the input cell is larger that the other priority, the input cell can extend and you could go to step 4. If the input cell has lower priority, it couldn't extend and you could make it a 1x1 room (or you could do the non-extending cell steps, which is necessary if you validate found cells in the hard check). If the priorities are equal, take the cell with the highest X or Y coordinate, or something.
In my example, the input cell has the highest priority, because it is bigger.
The final step. The cell is guaranteed to extend. You could calculate which walls exist. Notice that the left and the top wall always exist, as the extension cells are always in the top left corner.
Our cell could extend and we get this result:
Another example
The input cell:
Do the hard check:
Oh, it found one, so it couldn't extend and turns into a 1x1 room:
That's it, actually. I hope I've been clear enough. Rather than using squares, you could use rectangles too, or more complex shapes like L-shaped rooms.
And this is the final result of my example:

Comparing Distance within an Array

I have a question in comparing values within an Array and drawing a line to the points that have the largest distance.
Point2D[] pts = new Point2D[N];
for (int i = 0; i < pts.length; i++){
pts[i] = new Point2D(Math.random(), Math.random());
StdDraw.setPenColor(StdDraw.RED);
StdDraw.setPenRadius(0.008);
pts[i].draw();
if(SOMETHING){
StdDraw.setPenColor(StdDraw.BLACK);
StdDraw.setPenRadius(0.002);
pts[i].drawTo(SOMETHING);
so far that's part of my code that generates the random points, but I have no clue how to approach measuring the distance and then drawing it.
Would I have to create a nested loop?
Any advice would be great!
It is likely that, if you only want to draw the longest edge (a graph theory term), your draw call will not be inside of your for loop. Rather, your loop (and possibly with a second nested loop) will run through all of your possibilities and find the longest edge first, by saving and overwriting data on whichever is the most-longest it has found thus far every time it breaks the previous record, and then commence drawing once after the loop.

Do I always have to specify an index array to a Renderable in libGDX?

Right now I have a project set up with 2 meshes, which are rendering correctly by themselves.
My Objective is to add lighting to one of them(a surface I want to display), which is made up from GL10_GL_TRIANGLES, but not the other(a helper grid), which is (obviously) made up from GL10.GL_LINES.
So far I managed to compile the 2 into renderables, like so:
grid.mesh.setVertices(gridMeshArray);
grid.meshPartOffset = 0;
grid.meshPartSize = grid.mesh.getNumIndices();
grid.primitiveType = GL10.GL_LINES;
grid.material = new Material();
grid.bones = null;
sampleSurface.mesh.setVertices(meshVArray);
sampleSurface.mesh.setIndices(meshIArray);
sampleSurface.meshPartOffset = 0;
sampleSurface.meshPartSize = sampleSurface.mesh.getNumIndices();
sampleSurface.primitiveType = GL10.GL_TRIANGLES;
sampleSurface.material = new Material();
sampleSurface.bones = null;
When I run the program, I see the sampleSurface, but not the grid.
Rendering is as follows:
MB.begin(cam.getCam());
MB.render(sampleSurface);
MB.render(grid);
MB.end();
It's propably worth to mention, that I'm not using any shaders right now, just the command:
cam.apply(Gdx.gl10);
Which is'nt the best practice, and I'm planning to replace it once I have the time to dwelve into the topic.
My guess is, the grids won't display, because I didn't specify an index array to them. That seems to be the only difference between the two renderables. (not counting the environment, since changing grid.environment didn't have any effect.)
Defining an index array seems highly illogical for the grid, since it doesn't really have overlapping vertices. I'm not sure what to do, or where lies the problem, since the 2 meshes draw perfectly by themselves. Any help is appreciated!
http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g3d/Renderable.html#meshPartSize
The #meshPartSize member of Renderable is used to specify the size (in vertices) of the part of the mesh to render. When not rendering a strip this the number of primitives multiplied by the number of vertices per primitive. So if you want to render 4 triangles (GL_TRIANGLES), then the size is 12 (4 triangles * 3 vertices = 12 vertices total). If you want to render 12 lines (GL_LINES), then the size is 24 (12 lines * 2 vertices = 24 vertices total).
In practice this means that, if the mesh is indexed, the size is equal to the number of indices you want to render. If the mesh isn't indexed, then it's equal to the number vertices you want to render. A mesh is considered indexed if the number of indices it contains is greater than zero (mesh.getNumIndices() > 0).
To be specifc: if indexed then glDrawElements will be used with the offset and count arguments as specified. Otherwise glDrawArrays will be used with the offset and count arguments as specified.
That being said: please note that some classes might require indexed meshes, also note that GLES1.x might not be fully supported. So in practice it is advised to use indexed meshes and GLES2.
After a refreshing beer and a walk I read #Xoppa's answer, and it made me see my error.
Simply changing
grid.meshPartSize = grid.mesh.getNumIndices();
to
grid.meshPartSize = grid.mesh.getNumVertices();
solved my problem, now it displays correctly.

Understanding this recursive function

Hello fellow programmers.
For some time now, recursive programming have been one of the things i understand the least. Because of that i decided, that i needed to use some time, understanding and programming a few basic examples. The problem is that i have this assignment i solved, but dont quite understand how it works -.-
If someone could help me understand it, i would appreciate it.
Thanks, in advance.
Teilmann
Assignment:
A dominopiece has the size 2*1. A board has the length n and width 2. Create a recursive method that returns the number of ways, whereas a board can be covered by dominopieces.
My method:
public static int dominobrik(int n){
int sum;
if(n >= 0 && n <= 2){
sum = n;
} else {
sum = dominobrik(n-1) + dominobrik(n-2);
}
return sum;
}
To help people understand this kind of recursive calls I really think that nicely printing things out really helps.
The output of the program has been indented according to the recursion depth.
Here are the 8 paths taken to reach all the solution for a width of 5, when doing:
dominobrik(n-2) + dominobrik(n-1)
(notice that for each new path, the recursive calls first adds the two horizontal pieces if possible)
(also note that this is different than the code you posted, where you wrote (n-1) first and then (n-2), but it really doesn't change much)
So far the board is:
.....
.....
So far the board is:
--...
--...
So far the board is:
----.
----.
Finished board:
----|
----|
So far the board is:
--|..
--|..
Finished board:
--|--
--|--
So far the board is:
--||.
--||.
Finished board:
--|||
--|||
So far the board is:
|....
|....
So far the board is:
|--..
|--..
Finished board:
|----
|----
So far the board is:
|--|.
|--|.
Finished board:
|--||
|--||
So far the board is:
||...
||...
So far the board is:
||--.
||--.
Finished board:
||--|
||--|
So far the board is:
|||..
|||..
Finished board:
|||--
|||--
So far the board is:
||||.
||||.
Finished board:
|||||
|||||
In the base case, where n = 1, there is only 1 way to arrange the domino on the board, and that's horizontally. Where n = 2, there are 2 ways to arrange the dominoes. Either you can arrange both vertically, or both horizontally.
For the case where n = 3, the 3 ways are:
1 horizontally across the top, and two vertically beneath;
1 horizontally across the bottom, and 2 vertically above;
or all 3 horizontally, stacked.
Note that in the n = 3 case, you have repeated both of the arrangements of the n = 2 case, but to these, you have added the arrangement from the n = 1 case. Recall that the only valid arrangement for n = 1 is a single horizontal domino. Each of the cases in n = 3 has at least 1 horizontal domino.
You can extend this to the n = 4 case. Take all of the possible combinations above for n = 3, then add all of the combinations for n = 2, stacking them appropriately given the problem's constraints.
I wish I could illustrate this, but it may help to draw them out on some squared paper.
Le't say you know the answer for n and you want the answer for n + 1.
For some of the solutions for n, you have the last domino standing vertically and for the others, the last two dominos are stacked horizontally one over the other.
If the last two dominos are horizontal, all you can do is add your n + 1 domino vertically. However if the last domino is vertical, then you can add it vertically too, or you can flip it horizontally with the previous domino.
I would keep track not only of how many solutions there are for a given n, but also of how many of those are terminating with the last domino horizontal/vertical.
I'll let you figure out the rest since this is homework. Also I haven't really figured out the complete solution. It's possible it will turn out to be equivalent to the solution you posted.

Categories

Resources