Rectangle packing in smallest possible area
I have written a Java Program to place a bunch of rectangles
into the smallest possible rectangluar area(no overlapping and rotating).
Here is a short summary:
I calculate minArea and maxArea:
minArea: minArea is sum up all given rectangle areas.
maxArea: put all given rectangles side by side, maxArea is rectangle area in which all given rectangles fit in.
Between minArea and maxArea must exist the smallest rectangular area, in which all given rectangles fit in.
For each rectangular area between minArea and maxArea I try recursiv, if all given rectangles fit in the rectangular area.
Example input/output:
(height,width of rectangles)
2,3
4,4
5,5
7,2
1,1
9,3
1 1 1 2 2 2 2 6 6 6
1 1 1 2 2 2 2 6 6 6
4 4 5 2 2 2 2 6 6 6
4 4 0 2 2 2 2 6 6 6
4 4 3 3 3 3 3 6 6 6
4 4 3 3 3 3 3 6 6 6
4 4 3 3 3 3 3 6 6 6
4 4 3 3 3 3 3 6 6 6
4 4 3 3 3 3 3 6 6 6
0 represents free space, all other numbers are for differentiating rectangles.
RectanglePacking.java:
import java.util.ArrayList;
import java.util.Scanner;
import java.awt.Point;
import java.io.IOException;
class Rectangle {
public int id;
public int width;
public int height;
public Rectangle(int height, int width, int id) {
this.width = width;
this.height = height;
this.id = id;
}
}
public class RectanglePacking {
private ArrayList<Rectangle> rectangleList = new ArrayList<Rectangle>();
private int minArea;
private int maxArea;
private int getMinArea() {
for (Rectangle r : rectangleList) {
minArea = minArea + r.height * r.width;
}
return minArea;
}
private int getMaxArea() {
int totalWidth = 0;
int height = 0;
int maxHeight = 0;
for (Rectangle r : rectangleList) {
totalWidth = totalWidth + r.width;
height = r.height;
if (height >= maxHeight) {
maxHeight = height;
}
}
maxArea = totalWidth * maxHeight;
return maxArea;
}
private ArrayList<Point> possiblePlaces(int field, int id) {
ArrayList<Point> places = new ArrayList<Point>();
for (int i = 0; i < field.length; i++) {
for (int j = 0; j < field[0].length; j++) {
if (isEmpty(field, i, j, rectangleList.get(id).height, rectangleList.get(id).width)) {
places.add(new Point(i, j));
}
}
}
return places;
}
public boolean isEmpty(int field, int x, int y, int height, int width) {
for (int i = x; i < x + height; i++) {
for (int j = y; j < y + width; j++) {
if (i > field.length - 1 || j > field[0].length - 1 || field[i][j] != 0) {
return false;
}
}
}
return true;
}
private int markRectangle(int field, int x, int y, int height, int width, int id) {
id = id + 1;
for (int i = x; i < x + height; i++) {
for (int j = y; j < y + width; j++) {
field[i][j] = id;
}
}
return field;
}
private void removeRectangle(int field, int x, int y, int height, int width) {
for (int i = x; i < x + height; i++) {
for (int j = y; j < y + width; j++) {
field[i][j] = 0;
}
}
}
private void placeRectangles(int field, int id) {
if (id == rectangleList.size()) {
printSolution(field);
System.exit(0);
}
ArrayList<Point> possiblePlaces = possiblePlaces(field, id);
for (int i = 0; i < possiblePlaces.size(); i++) {
Point p = possiblePlaces.get(i);
field = markRectangle(field, p.x, p.y, rectangleList.get(id).height, rectangleList.get(id).width, id);
placeRectangles(field, id + 1);
removeRectangle(field, p.x, p.y, rectangleList.get(id).height, rectangleList.get(id).width);
}
}
private ArrayList<Point> calcPossibleAreas() {
ArrayList<Point> possibleAreas= new ArrayList<Point>();
ArrayList<Point> factors = new ArrayList<Point>();
for (int i = getMinArea(); i <= getMaxArea(); i++) {
factors = calcFactors(i);
for (int j = 0; j < factors.size(); j++) {
possibleAreas.add(new Point(factors.get(j).x, factors.get(j).y));
}
}
return possibleAreas;
}
private ArrayList<Point> calcFactors(int number) {
ArrayList<Point> factors = new ArrayList<Point>();
for (int i = 1; i <= number; i++) {
if (number % i == 0) {
factors.add(new Point(i, number/i));
factors.add(new Point(number/i, i));
}
}
return factors;
}
private void calcMinArea() {
ArrayList<Point> possibleAreas = calcPossibleAreas();
int field;
for (int i = 0; i < possibleAreas.size(); i++) {
int x = possibleAreas.get(i).x;
int y = possibleAreas.get(i).y;
field = new int[x][y];
placeRectangles(field, 0);
}
}
private void printSolution(int field) {
System.out.println("Solution:");
for (int i = 0; i < field.length; i++) {
for (int j = 0; j < field[0].length; j++) {
System.out.print(" "+field[i][j] + " ");
}
System.out.println();
}
}
public static void main(String args) throws IOException {
RectanglePacking r = new RectanglePacking();
Scanner input = new Scanner(System.in);
int id = 1;
try {
while (true) {
String line = input.nextLine();
if (line.equals("")) {
break;
}
String split = line.split(",");
int height = Integer.parseInt(split[0]);
int width = Integer.parseInt(split[1]);
r.rectangleList.add(new Rectangle(height, width, id));
id++;
}
input.close();
} catch (Exception ex) {
ex.printStackTrace();
}
r.calcMinArea();
}
}
How can I improve my code?
Any help is really appreciated.
java performance recursion
add a comment |
I have written a Java Program to place a bunch of rectangles
into the smallest possible rectangluar area(no overlapping and rotating).
Here is a short summary:
I calculate minArea and maxArea:
minArea: minArea is sum up all given rectangle areas.
maxArea: put all given rectangles side by side, maxArea is rectangle area in which all given rectangles fit in.
Between minArea and maxArea must exist the smallest rectangular area, in which all given rectangles fit in.
For each rectangular area between minArea and maxArea I try recursiv, if all given rectangles fit in the rectangular area.
Example input/output:
(height,width of rectangles)
2,3
4,4
5,5
7,2
1,1
9,3
1 1 1 2 2 2 2 6 6 6
1 1 1 2 2 2 2 6 6 6
4 4 5 2 2 2 2 6 6 6
4 4 0 2 2 2 2 6 6 6
4 4 3 3 3 3 3 6 6 6
4 4 3 3 3 3 3 6 6 6
4 4 3 3 3 3 3 6 6 6
4 4 3 3 3 3 3 6 6 6
4 4 3 3 3 3 3 6 6 6
0 represents free space, all other numbers are for differentiating rectangles.
RectanglePacking.java:
import java.util.ArrayList;
import java.util.Scanner;
import java.awt.Point;
import java.io.IOException;
class Rectangle {
public int id;
public int width;
public int height;
public Rectangle(int height, int width, int id) {
this.width = width;
this.height = height;
this.id = id;
}
}
public class RectanglePacking {
private ArrayList<Rectangle> rectangleList = new ArrayList<Rectangle>();
private int minArea;
private int maxArea;
private int getMinArea() {
for (Rectangle r : rectangleList) {
minArea = minArea + r.height * r.width;
}
return minArea;
}
private int getMaxArea() {
int totalWidth = 0;
int height = 0;
int maxHeight = 0;
for (Rectangle r : rectangleList) {
totalWidth = totalWidth + r.width;
height = r.height;
if (height >= maxHeight) {
maxHeight = height;
}
}
maxArea = totalWidth * maxHeight;
return maxArea;
}
private ArrayList<Point> possiblePlaces(int field, int id) {
ArrayList<Point> places = new ArrayList<Point>();
for (int i = 0; i < field.length; i++) {
for (int j = 0; j < field[0].length; j++) {
if (isEmpty(field, i, j, rectangleList.get(id).height, rectangleList.get(id).width)) {
places.add(new Point(i, j));
}
}
}
return places;
}
public boolean isEmpty(int field, int x, int y, int height, int width) {
for (int i = x; i < x + height; i++) {
for (int j = y; j < y + width; j++) {
if (i > field.length - 1 || j > field[0].length - 1 || field[i][j] != 0) {
return false;
}
}
}
return true;
}
private int markRectangle(int field, int x, int y, int height, int width, int id) {
id = id + 1;
for (int i = x; i < x + height; i++) {
for (int j = y; j < y + width; j++) {
field[i][j] = id;
}
}
return field;
}
private void removeRectangle(int field, int x, int y, int height, int width) {
for (int i = x; i < x + height; i++) {
for (int j = y; j < y + width; j++) {
field[i][j] = 0;
}
}
}
private void placeRectangles(int field, int id) {
if (id == rectangleList.size()) {
printSolution(field);
System.exit(0);
}
ArrayList<Point> possiblePlaces = possiblePlaces(field, id);
for (int i = 0; i < possiblePlaces.size(); i++) {
Point p = possiblePlaces.get(i);
field = markRectangle(field, p.x, p.y, rectangleList.get(id).height, rectangleList.get(id).width, id);
placeRectangles(field, id + 1);
removeRectangle(field, p.x, p.y, rectangleList.get(id).height, rectangleList.get(id).width);
}
}
private ArrayList<Point> calcPossibleAreas() {
ArrayList<Point> possibleAreas= new ArrayList<Point>();
ArrayList<Point> factors = new ArrayList<Point>();
for (int i = getMinArea(); i <= getMaxArea(); i++) {
factors = calcFactors(i);
for (int j = 0; j < factors.size(); j++) {
possibleAreas.add(new Point(factors.get(j).x, factors.get(j).y));
}
}
return possibleAreas;
}
private ArrayList<Point> calcFactors(int number) {
ArrayList<Point> factors = new ArrayList<Point>();
for (int i = 1; i <= number; i++) {
if (number % i == 0) {
factors.add(new Point(i, number/i));
factors.add(new Point(number/i, i));
}
}
return factors;
}
private void calcMinArea() {
ArrayList<Point> possibleAreas = calcPossibleAreas();
int field;
for (int i = 0; i < possibleAreas.size(); i++) {
int x = possibleAreas.get(i).x;
int y = possibleAreas.get(i).y;
field = new int[x][y];
placeRectangles(field, 0);
}
}
private void printSolution(int field) {
System.out.println("Solution:");
for (int i = 0; i < field.length; i++) {
for (int j = 0; j < field[0].length; j++) {
System.out.print(" "+field[i][j] + " ");
}
System.out.println();
}
}
public static void main(String args) throws IOException {
RectanglePacking r = new RectanglePacking();
Scanner input = new Scanner(System.in);
int id = 1;
try {
while (true) {
String line = input.nextLine();
if (line.equals("")) {
break;
}
String split = line.split(",");
int height = Integer.parseInt(split[0]);
int width = Integer.parseInt(split[1]);
r.rectangleList.add(new Rectangle(height, width, id));
id++;
}
input.close();
} catch (Exception ex) {
ex.printStackTrace();
}
r.calcMinArea();
}
}
How can I improve my code?
Any help is really appreciated.
java performance recursion
Change your algortihm to ijcai.org/Proceedings/09/Papers/092.pdf
– RobAu
yesterday
add a comment |
I have written a Java Program to place a bunch of rectangles
into the smallest possible rectangluar area(no overlapping and rotating).
Here is a short summary:
I calculate minArea and maxArea:
minArea: minArea is sum up all given rectangle areas.
maxArea: put all given rectangles side by side, maxArea is rectangle area in which all given rectangles fit in.
Between minArea and maxArea must exist the smallest rectangular area, in which all given rectangles fit in.
For each rectangular area between minArea and maxArea I try recursiv, if all given rectangles fit in the rectangular area.
Example input/output:
(height,width of rectangles)
2,3
4,4
5,5
7,2
1,1
9,3
1 1 1 2 2 2 2 6 6 6
1 1 1 2 2 2 2 6 6 6
4 4 5 2 2 2 2 6 6 6
4 4 0 2 2 2 2 6 6 6
4 4 3 3 3 3 3 6 6 6
4 4 3 3 3 3 3 6 6 6
4 4 3 3 3 3 3 6 6 6
4 4 3 3 3 3 3 6 6 6
4 4 3 3 3 3 3 6 6 6
0 represents free space, all other numbers are for differentiating rectangles.
RectanglePacking.java:
import java.util.ArrayList;
import java.util.Scanner;
import java.awt.Point;
import java.io.IOException;
class Rectangle {
public int id;
public int width;
public int height;
public Rectangle(int height, int width, int id) {
this.width = width;
this.height = height;
this.id = id;
}
}
public class RectanglePacking {
private ArrayList<Rectangle> rectangleList = new ArrayList<Rectangle>();
private int minArea;
private int maxArea;
private int getMinArea() {
for (Rectangle r : rectangleList) {
minArea = minArea + r.height * r.width;
}
return minArea;
}
private int getMaxArea() {
int totalWidth = 0;
int height = 0;
int maxHeight = 0;
for (Rectangle r : rectangleList) {
totalWidth = totalWidth + r.width;
height = r.height;
if (height >= maxHeight) {
maxHeight = height;
}
}
maxArea = totalWidth * maxHeight;
return maxArea;
}
private ArrayList<Point> possiblePlaces(int field, int id) {
ArrayList<Point> places = new ArrayList<Point>();
for (int i = 0; i < field.length; i++) {
for (int j = 0; j < field[0].length; j++) {
if (isEmpty(field, i, j, rectangleList.get(id).height, rectangleList.get(id).width)) {
places.add(new Point(i, j));
}
}
}
return places;
}
public boolean isEmpty(int field, int x, int y, int height, int width) {
for (int i = x; i < x + height; i++) {
for (int j = y; j < y + width; j++) {
if (i > field.length - 1 || j > field[0].length - 1 || field[i][j] != 0) {
return false;
}
}
}
return true;
}
private int markRectangle(int field, int x, int y, int height, int width, int id) {
id = id + 1;
for (int i = x; i < x + height; i++) {
for (int j = y; j < y + width; j++) {
field[i][j] = id;
}
}
return field;
}
private void removeRectangle(int field, int x, int y, int height, int width) {
for (int i = x; i < x + height; i++) {
for (int j = y; j < y + width; j++) {
field[i][j] = 0;
}
}
}
private void placeRectangles(int field, int id) {
if (id == rectangleList.size()) {
printSolution(field);
System.exit(0);
}
ArrayList<Point> possiblePlaces = possiblePlaces(field, id);
for (int i = 0; i < possiblePlaces.size(); i++) {
Point p = possiblePlaces.get(i);
field = markRectangle(field, p.x, p.y, rectangleList.get(id).height, rectangleList.get(id).width, id);
placeRectangles(field, id + 1);
removeRectangle(field, p.x, p.y, rectangleList.get(id).height, rectangleList.get(id).width);
}
}
private ArrayList<Point> calcPossibleAreas() {
ArrayList<Point> possibleAreas= new ArrayList<Point>();
ArrayList<Point> factors = new ArrayList<Point>();
for (int i = getMinArea(); i <= getMaxArea(); i++) {
factors = calcFactors(i);
for (int j = 0; j < factors.size(); j++) {
possibleAreas.add(new Point(factors.get(j).x, factors.get(j).y));
}
}
return possibleAreas;
}
private ArrayList<Point> calcFactors(int number) {
ArrayList<Point> factors = new ArrayList<Point>();
for (int i = 1; i <= number; i++) {
if (number % i == 0) {
factors.add(new Point(i, number/i));
factors.add(new Point(number/i, i));
}
}
return factors;
}
private void calcMinArea() {
ArrayList<Point> possibleAreas = calcPossibleAreas();
int field;
for (int i = 0; i < possibleAreas.size(); i++) {
int x = possibleAreas.get(i).x;
int y = possibleAreas.get(i).y;
field = new int[x][y];
placeRectangles(field, 0);
}
}
private void printSolution(int field) {
System.out.println("Solution:");
for (int i = 0; i < field.length; i++) {
for (int j = 0; j < field[0].length; j++) {
System.out.print(" "+field[i][j] + " ");
}
System.out.println();
}
}
public static void main(String args) throws IOException {
RectanglePacking r = new RectanglePacking();
Scanner input = new Scanner(System.in);
int id = 1;
try {
while (true) {
String line = input.nextLine();
if (line.equals("")) {
break;
}
String split = line.split(",");
int height = Integer.parseInt(split[0]);
int width = Integer.parseInt(split[1]);
r.rectangleList.add(new Rectangle(height, width, id));
id++;
}
input.close();
} catch (Exception ex) {
ex.printStackTrace();
}
r.calcMinArea();
}
}
How can I improve my code?
Any help is really appreciated.
java performance recursion
I have written a Java Program to place a bunch of rectangles
into the smallest possible rectangluar area(no overlapping and rotating).
Here is a short summary:
I calculate minArea and maxArea:
minArea: minArea is sum up all given rectangle areas.
maxArea: put all given rectangles side by side, maxArea is rectangle area in which all given rectangles fit in.
Between minArea and maxArea must exist the smallest rectangular area, in which all given rectangles fit in.
For each rectangular area between minArea and maxArea I try recursiv, if all given rectangles fit in the rectangular area.
Example input/output:
(height,width of rectangles)
2,3
4,4
5,5
7,2
1,1
9,3
1 1 1 2 2 2 2 6 6 6
1 1 1 2 2 2 2 6 6 6
4 4 5 2 2 2 2 6 6 6
4 4 0 2 2 2 2 6 6 6
4 4 3 3 3 3 3 6 6 6
4 4 3 3 3 3 3 6 6 6
4 4 3 3 3 3 3 6 6 6
4 4 3 3 3 3 3 6 6 6
4 4 3 3 3 3 3 6 6 6
0 represents free space, all other numbers are for differentiating rectangles.
RectanglePacking.java:
import java.util.ArrayList;
import java.util.Scanner;
import java.awt.Point;
import java.io.IOException;
class Rectangle {
public int id;
public int width;
public int height;
public Rectangle(int height, int width, int id) {
this.width = width;
this.height = height;
this.id = id;
}
}
public class RectanglePacking {
private ArrayList<Rectangle> rectangleList = new ArrayList<Rectangle>();
private int minArea;
private int maxArea;
private int getMinArea() {
for (Rectangle r : rectangleList) {
minArea = minArea + r.height * r.width;
}
return minArea;
}
private int getMaxArea() {
int totalWidth = 0;
int height = 0;
int maxHeight = 0;
for (Rectangle r : rectangleList) {
totalWidth = totalWidth + r.width;
height = r.height;
if (height >= maxHeight) {
maxHeight = height;
}
}
maxArea = totalWidth * maxHeight;
return maxArea;
}
private ArrayList<Point> possiblePlaces(int field, int id) {
ArrayList<Point> places = new ArrayList<Point>();
for (int i = 0; i < field.length; i++) {
for (int j = 0; j < field[0].length; j++) {
if (isEmpty(field, i, j, rectangleList.get(id).height, rectangleList.get(id).width)) {
places.add(new Point(i, j));
}
}
}
return places;
}
public boolean isEmpty(int field, int x, int y, int height, int width) {
for (int i = x; i < x + height; i++) {
for (int j = y; j < y + width; j++) {
if (i > field.length - 1 || j > field[0].length - 1 || field[i][j] != 0) {
return false;
}
}
}
return true;
}
private int markRectangle(int field, int x, int y, int height, int width, int id) {
id = id + 1;
for (int i = x; i < x + height; i++) {
for (int j = y; j < y + width; j++) {
field[i][j] = id;
}
}
return field;
}
private void removeRectangle(int field, int x, int y, int height, int width) {
for (int i = x; i < x + height; i++) {
for (int j = y; j < y + width; j++) {
field[i][j] = 0;
}
}
}
private void placeRectangles(int field, int id) {
if (id == rectangleList.size()) {
printSolution(field);
System.exit(0);
}
ArrayList<Point> possiblePlaces = possiblePlaces(field, id);
for (int i = 0; i < possiblePlaces.size(); i++) {
Point p = possiblePlaces.get(i);
field = markRectangle(field, p.x, p.y, rectangleList.get(id).height, rectangleList.get(id).width, id);
placeRectangles(field, id + 1);
removeRectangle(field, p.x, p.y, rectangleList.get(id).height, rectangleList.get(id).width);
}
}
private ArrayList<Point> calcPossibleAreas() {
ArrayList<Point> possibleAreas= new ArrayList<Point>();
ArrayList<Point> factors = new ArrayList<Point>();
for (int i = getMinArea(); i <= getMaxArea(); i++) {
factors = calcFactors(i);
for (int j = 0; j < factors.size(); j++) {
possibleAreas.add(new Point(factors.get(j).x, factors.get(j).y));
}
}
return possibleAreas;
}
private ArrayList<Point> calcFactors(int number) {
ArrayList<Point> factors = new ArrayList<Point>();
for (int i = 1; i <= number; i++) {
if (number % i == 0) {
factors.add(new Point(i, number/i));
factors.add(new Point(number/i, i));
}
}
return factors;
}
private void calcMinArea() {
ArrayList<Point> possibleAreas = calcPossibleAreas();
int field;
for (int i = 0; i < possibleAreas.size(); i++) {
int x = possibleAreas.get(i).x;
int y = possibleAreas.get(i).y;
field = new int[x][y];
placeRectangles(field, 0);
}
}
private void printSolution(int field) {
System.out.println("Solution:");
for (int i = 0; i < field.length; i++) {
for (int j = 0; j < field[0].length; j++) {
System.out.print(" "+field[i][j] + " ");
}
System.out.println();
}
}
public static void main(String args) throws IOException {
RectanglePacking r = new RectanglePacking();
Scanner input = new Scanner(System.in);
int id = 1;
try {
while (true) {
String line = input.nextLine();
if (line.equals("")) {
break;
}
String split = line.split(",");
int height = Integer.parseInt(split[0]);
int width = Integer.parseInt(split[1]);
r.rectangleList.add(new Rectangle(height, width, id));
id++;
}
input.close();
} catch (Exception ex) {
ex.printStackTrace();
}
r.calcMinArea();
}
}
How can I improve my code?
Any help is really appreciated.
java performance recursion
java performance recursion
asked Jan 1 at 20:25
Marten
1607
1607
Change your algortihm to ijcai.org/Proceedings/09/Papers/092.pdf
– RobAu
yesterday
add a comment |
Change your algortihm to ijcai.org/Proceedings/09/Papers/092.pdf
– RobAu
yesterday
Change your algortihm to ijcai.org/Proceedings/09/Papers/092.pdf
– RobAu
yesterday
Change your algortihm to ijcai.org/Proceedings/09/Papers/092.pdf
– RobAu
yesterday
add a comment |
1 Answer
1
active
oldest
votes
For each rectangular area between minArea and maxArea I [test recursively] if all given rectangles fit in the rectangular area.
My first comment is that this subproblem seems like a perfect application for Dancing Links.
It won't solve your entire problem (the "area minimization" problem), but it will very quickly solve your subproblem (the "can I fit all the rectangles into this other rectangle" problem).
It is weird that your markRectangle
function returns a value (the value of field
, which is just its first parameter), but your removeRectangle
function returns void. I would expect both of them to return void.
Let's see how you compute "each rectangular area between minArea and maxArea". Slightly reformatted for whitespace:
private ArrayList<Point> calcPossibleAreas() {
ArrayList<Point> possibleAreas = new ArrayList<Point>();
ArrayList<Point> factors = new ArrayList<Point>();
for (int i = getMinArea(); i <= getMaxArea(); ++i) {
factors = calcFactors(i);
for (int j = 0; j < factors.size(); ++j) {
possibleAreas.add(new Point(factors.get(j).x, factors.get(j).y));
}
}
return possibleAreas;
}
Calculating getMaxArea()
every time through the loop is silly. Also, you set factors
to new ArrayList<Point>()
at the top of the function, and then immediately throw away that value by assigning it a new value inside the loop. So at the bare minimum, I'd expect
private ArrayList<Point> calcPossibleAreas() {
ArrayList<Point> possibleAreas = new ArrayList<Point>();
int maxArea = getMaxArea();
for (int i = getMinArea(); i <= maxArea; ++i) {
ArrayList<Point> factors = calcFactors(i);
for (int j = 0; j < factors.size(); ++j) {
possibleAreas.add(factors.get(j));
}
}
return possibleAreas;
}
And then (AFAIK) you can use Java 5's for
-each loop:
private ArrayList<Point> calcPossibleAreas() {
ArrayList<Point> possibleAreas = new ArrayList<Point>();
int maxArea = getMaxArea();
for (int i = getMinArea(); i <= maxArea; ++i) {
for (Point factor : calcFactors(i)) {
possibleAreas.add(factor);
}
}
return possibleAreas;
}
But all that calcFactors
is expensive; and you wind up with a lot of 2xN rectangles that can't possibly be filled. So I would rather write it like this:
private ArrayList<Point> calcPossibleAreas() {
ArrayList<Point> possibleAreas = new ArrayList<Point>();
int minWidth = 0;
int maxWidth = 0;
int minHeight = 0;
int maxHeight = 0;
int minArea = 0;
for (Rectangle r : rectangleList) {
minWidth = Math.max(minWidth, r.width);
minHeight = Math.max(minHeight, r.height);
maxWidth += r.width;
maxHeight += r.height;
minArea += r.width * r.height;
}
int maxArea = Math.min(maxWidth * minHeight, minWidth * maxHeight);
for (int x = minWidth; x <= maxWidth; ++x) {
for (int y = minHeight; y <= maxHeight; ++y) {
if (minArea <= x * y && x * y <= maxArea) {
possibleAreas.add(new Point(x, y));
}
}
}
// Now sort possibleAreas so we'll try the smaller rectangles first.
Collections.sort(possibleAreas, new Comparator<Point>() {
@Override
public int compare(Point lhs, Point rhs) {
int la = (lhs.x * lhs.y), ra = (rhs.x * rhs.y);
return (la < ra) ? -1 : (la > ra);
}
});
}
Of course, calcPossibleAreas()
is just a preliminary step that will be very fast compared to placeRectangles()
. So Amdahl's Law says that you (and I ;)) should spend time optimizing placeRectangles()
rather than calcPossibleAreas()
. I would recommend looking at some way to eliminate the O(w*h)
writes to field
— is there some way you can express "all these positions are filled" without actually doing the O(w*h)
writes? Vice versa, is there some way you can test "is this a valid placement for my current rectangle" without doing O(w*h)
reads?
Rather than looking for places to put each rectangle, it might be better to look for ways to fill each point in the target. Pretend you have your set of rectangles, plus just enough "spare" 1x1 rectangles to fill up the empty spaces. If you try to fill all the points in the target, working downward from the upper left corner, then you have to try each rectangle in only one position — and you can skip rectangles that are too wide or tall to fit — and if none of your rectangles fit, and you're out of spare 1x1s, then you know it's time to backtrack. (This is essentially how Dancing Links would do it.)
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210711%2frectangle-packing-in-smallest-possible-area%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
For each rectangular area between minArea and maxArea I [test recursively] if all given rectangles fit in the rectangular area.
My first comment is that this subproblem seems like a perfect application for Dancing Links.
It won't solve your entire problem (the "area minimization" problem), but it will very quickly solve your subproblem (the "can I fit all the rectangles into this other rectangle" problem).
It is weird that your markRectangle
function returns a value (the value of field
, which is just its first parameter), but your removeRectangle
function returns void. I would expect both of them to return void.
Let's see how you compute "each rectangular area between minArea and maxArea". Slightly reformatted for whitespace:
private ArrayList<Point> calcPossibleAreas() {
ArrayList<Point> possibleAreas = new ArrayList<Point>();
ArrayList<Point> factors = new ArrayList<Point>();
for (int i = getMinArea(); i <= getMaxArea(); ++i) {
factors = calcFactors(i);
for (int j = 0; j < factors.size(); ++j) {
possibleAreas.add(new Point(factors.get(j).x, factors.get(j).y));
}
}
return possibleAreas;
}
Calculating getMaxArea()
every time through the loop is silly. Also, you set factors
to new ArrayList<Point>()
at the top of the function, and then immediately throw away that value by assigning it a new value inside the loop. So at the bare minimum, I'd expect
private ArrayList<Point> calcPossibleAreas() {
ArrayList<Point> possibleAreas = new ArrayList<Point>();
int maxArea = getMaxArea();
for (int i = getMinArea(); i <= maxArea; ++i) {
ArrayList<Point> factors = calcFactors(i);
for (int j = 0; j < factors.size(); ++j) {
possibleAreas.add(factors.get(j));
}
}
return possibleAreas;
}
And then (AFAIK) you can use Java 5's for
-each loop:
private ArrayList<Point> calcPossibleAreas() {
ArrayList<Point> possibleAreas = new ArrayList<Point>();
int maxArea = getMaxArea();
for (int i = getMinArea(); i <= maxArea; ++i) {
for (Point factor : calcFactors(i)) {
possibleAreas.add(factor);
}
}
return possibleAreas;
}
But all that calcFactors
is expensive; and you wind up with a lot of 2xN rectangles that can't possibly be filled. So I would rather write it like this:
private ArrayList<Point> calcPossibleAreas() {
ArrayList<Point> possibleAreas = new ArrayList<Point>();
int minWidth = 0;
int maxWidth = 0;
int minHeight = 0;
int maxHeight = 0;
int minArea = 0;
for (Rectangle r : rectangleList) {
minWidth = Math.max(minWidth, r.width);
minHeight = Math.max(minHeight, r.height);
maxWidth += r.width;
maxHeight += r.height;
minArea += r.width * r.height;
}
int maxArea = Math.min(maxWidth * minHeight, minWidth * maxHeight);
for (int x = minWidth; x <= maxWidth; ++x) {
for (int y = minHeight; y <= maxHeight; ++y) {
if (minArea <= x * y && x * y <= maxArea) {
possibleAreas.add(new Point(x, y));
}
}
}
// Now sort possibleAreas so we'll try the smaller rectangles first.
Collections.sort(possibleAreas, new Comparator<Point>() {
@Override
public int compare(Point lhs, Point rhs) {
int la = (lhs.x * lhs.y), ra = (rhs.x * rhs.y);
return (la < ra) ? -1 : (la > ra);
}
});
}
Of course, calcPossibleAreas()
is just a preliminary step that will be very fast compared to placeRectangles()
. So Amdahl's Law says that you (and I ;)) should spend time optimizing placeRectangles()
rather than calcPossibleAreas()
. I would recommend looking at some way to eliminate the O(w*h)
writes to field
— is there some way you can express "all these positions are filled" without actually doing the O(w*h)
writes? Vice versa, is there some way you can test "is this a valid placement for my current rectangle" without doing O(w*h)
reads?
Rather than looking for places to put each rectangle, it might be better to look for ways to fill each point in the target. Pretend you have your set of rectangles, plus just enough "spare" 1x1 rectangles to fill up the empty spaces. If you try to fill all the points in the target, working downward from the upper left corner, then you have to try each rectangle in only one position — and you can skip rectangles that are too wide or tall to fit — and if none of your rectangles fit, and you're out of spare 1x1s, then you know it's time to backtrack. (This is essentially how Dancing Links would do it.)
add a comment |
For each rectangular area between minArea and maxArea I [test recursively] if all given rectangles fit in the rectangular area.
My first comment is that this subproblem seems like a perfect application for Dancing Links.
It won't solve your entire problem (the "area minimization" problem), but it will very quickly solve your subproblem (the "can I fit all the rectangles into this other rectangle" problem).
It is weird that your markRectangle
function returns a value (the value of field
, which is just its first parameter), but your removeRectangle
function returns void. I would expect both of them to return void.
Let's see how you compute "each rectangular area between minArea and maxArea". Slightly reformatted for whitespace:
private ArrayList<Point> calcPossibleAreas() {
ArrayList<Point> possibleAreas = new ArrayList<Point>();
ArrayList<Point> factors = new ArrayList<Point>();
for (int i = getMinArea(); i <= getMaxArea(); ++i) {
factors = calcFactors(i);
for (int j = 0; j < factors.size(); ++j) {
possibleAreas.add(new Point(factors.get(j).x, factors.get(j).y));
}
}
return possibleAreas;
}
Calculating getMaxArea()
every time through the loop is silly. Also, you set factors
to new ArrayList<Point>()
at the top of the function, and then immediately throw away that value by assigning it a new value inside the loop. So at the bare minimum, I'd expect
private ArrayList<Point> calcPossibleAreas() {
ArrayList<Point> possibleAreas = new ArrayList<Point>();
int maxArea = getMaxArea();
for (int i = getMinArea(); i <= maxArea; ++i) {
ArrayList<Point> factors = calcFactors(i);
for (int j = 0; j < factors.size(); ++j) {
possibleAreas.add(factors.get(j));
}
}
return possibleAreas;
}
And then (AFAIK) you can use Java 5's for
-each loop:
private ArrayList<Point> calcPossibleAreas() {
ArrayList<Point> possibleAreas = new ArrayList<Point>();
int maxArea = getMaxArea();
for (int i = getMinArea(); i <= maxArea; ++i) {
for (Point factor : calcFactors(i)) {
possibleAreas.add(factor);
}
}
return possibleAreas;
}
But all that calcFactors
is expensive; and you wind up with a lot of 2xN rectangles that can't possibly be filled. So I would rather write it like this:
private ArrayList<Point> calcPossibleAreas() {
ArrayList<Point> possibleAreas = new ArrayList<Point>();
int minWidth = 0;
int maxWidth = 0;
int minHeight = 0;
int maxHeight = 0;
int minArea = 0;
for (Rectangle r : rectangleList) {
minWidth = Math.max(minWidth, r.width);
minHeight = Math.max(minHeight, r.height);
maxWidth += r.width;
maxHeight += r.height;
minArea += r.width * r.height;
}
int maxArea = Math.min(maxWidth * minHeight, minWidth * maxHeight);
for (int x = minWidth; x <= maxWidth; ++x) {
for (int y = minHeight; y <= maxHeight; ++y) {
if (minArea <= x * y && x * y <= maxArea) {
possibleAreas.add(new Point(x, y));
}
}
}
// Now sort possibleAreas so we'll try the smaller rectangles first.
Collections.sort(possibleAreas, new Comparator<Point>() {
@Override
public int compare(Point lhs, Point rhs) {
int la = (lhs.x * lhs.y), ra = (rhs.x * rhs.y);
return (la < ra) ? -1 : (la > ra);
}
});
}
Of course, calcPossibleAreas()
is just a preliminary step that will be very fast compared to placeRectangles()
. So Amdahl's Law says that you (and I ;)) should spend time optimizing placeRectangles()
rather than calcPossibleAreas()
. I would recommend looking at some way to eliminate the O(w*h)
writes to field
— is there some way you can express "all these positions are filled" without actually doing the O(w*h)
writes? Vice versa, is there some way you can test "is this a valid placement for my current rectangle" without doing O(w*h)
reads?
Rather than looking for places to put each rectangle, it might be better to look for ways to fill each point in the target. Pretend you have your set of rectangles, plus just enough "spare" 1x1 rectangles to fill up the empty spaces. If you try to fill all the points in the target, working downward from the upper left corner, then you have to try each rectangle in only one position — and you can skip rectangles that are too wide or tall to fit — and if none of your rectangles fit, and you're out of spare 1x1s, then you know it's time to backtrack. (This is essentially how Dancing Links would do it.)
add a comment |
For each rectangular area between minArea and maxArea I [test recursively] if all given rectangles fit in the rectangular area.
My first comment is that this subproblem seems like a perfect application for Dancing Links.
It won't solve your entire problem (the "area minimization" problem), but it will very quickly solve your subproblem (the "can I fit all the rectangles into this other rectangle" problem).
It is weird that your markRectangle
function returns a value (the value of field
, which is just its first parameter), but your removeRectangle
function returns void. I would expect both of them to return void.
Let's see how you compute "each rectangular area between minArea and maxArea". Slightly reformatted for whitespace:
private ArrayList<Point> calcPossibleAreas() {
ArrayList<Point> possibleAreas = new ArrayList<Point>();
ArrayList<Point> factors = new ArrayList<Point>();
for (int i = getMinArea(); i <= getMaxArea(); ++i) {
factors = calcFactors(i);
for (int j = 0; j < factors.size(); ++j) {
possibleAreas.add(new Point(factors.get(j).x, factors.get(j).y));
}
}
return possibleAreas;
}
Calculating getMaxArea()
every time through the loop is silly. Also, you set factors
to new ArrayList<Point>()
at the top of the function, and then immediately throw away that value by assigning it a new value inside the loop. So at the bare minimum, I'd expect
private ArrayList<Point> calcPossibleAreas() {
ArrayList<Point> possibleAreas = new ArrayList<Point>();
int maxArea = getMaxArea();
for (int i = getMinArea(); i <= maxArea; ++i) {
ArrayList<Point> factors = calcFactors(i);
for (int j = 0; j < factors.size(); ++j) {
possibleAreas.add(factors.get(j));
}
}
return possibleAreas;
}
And then (AFAIK) you can use Java 5's for
-each loop:
private ArrayList<Point> calcPossibleAreas() {
ArrayList<Point> possibleAreas = new ArrayList<Point>();
int maxArea = getMaxArea();
for (int i = getMinArea(); i <= maxArea; ++i) {
for (Point factor : calcFactors(i)) {
possibleAreas.add(factor);
}
}
return possibleAreas;
}
But all that calcFactors
is expensive; and you wind up with a lot of 2xN rectangles that can't possibly be filled. So I would rather write it like this:
private ArrayList<Point> calcPossibleAreas() {
ArrayList<Point> possibleAreas = new ArrayList<Point>();
int minWidth = 0;
int maxWidth = 0;
int minHeight = 0;
int maxHeight = 0;
int minArea = 0;
for (Rectangle r : rectangleList) {
minWidth = Math.max(minWidth, r.width);
minHeight = Math.max(minHeight, r.height);
maxWidth += r.width;
maxHeight += r.height;
minArea += r.width * r.height;
}
int maxArea = Math.min(maxWidth * minHeight, minWidth * maxHeight);
for (int x = minWidth; x <= maxWidth; ++x) {
for (int y = minHeight; y <= maxHeight; ++y) {
if (minArea <= x * y && x * y <= maxArea) {
possibleAreas.add(new Point(x, y));
}
}
}
// Now sort possibleAreas so we'll try the smaller rectangles first.
Collections.sort(possibleAreas, new Comparator<Point>() {
@Override
public int compare(Point lhs, Point rhs) {
int la = (lhs.x * lhs.y), ra = (rhs.x * rhs.y);
return (la < ra) ? -1 : (la > ra);
}
});
}
Of course, calcPossibleAreas()
is just a preliminary step that will be very fast compared to placeRectangles()
. So Amdahl's Law says that you (and I ;)) should spend time optimizing placeRectangles()
rather than calcPossibleAreas()
. I would recommend looking at some way to eliminate the O(w*h)
writes to field
— is there some way you can express "all these positions are filled" without actually doing the O(w*h)
writes? Vice versa, is there some way you can test "is this a valid placement for my current rectangle" without doing O(w*h)
reads?
Rather than looking for places to put each rectangle, it might be better to look for ways to fill each point in the target. Pretend you have your set of rectangles, plus just enough "spare" 1x1 rectangles to fill up the empty spaces. If you try to fill all the points in the target, working downward from the upper left corner, then you have to try each rectangle in only one position — and you can skip rectangles that are too wide or tall to fit — and if none of your rectangles fit, and you're out of spare 1x1s, then you know it's time to backtrack. (This is essentially how Dancing Links would do it.)
For each rectangular area between minArea and maxArea I [test recursively] if all given rectangles fit in the rectangular area.
My first comment is that this subproblem seems like a perfect application for Dancing Links.
It won't solve your entire problem (the "area minimization" problem), but it will very quickly solve your subproblem (the "can I fit all the rectangles into this other rectangle" problem).
It is weird that your markRectangle
function returns a value (the value of field
, which is just its first parameter), but your removeRectangle
function returns void. I would expect both of them to return void.
Let's see how you compute "each rectangular area between minArea and maxArea". Slightly reformatted for whitespace:
private ArrayList<Point> calcPossibleAreas() {
ArrayList<Point> possibleAreas = new ArrayList<Point>();
ArrayList<Point> factors = new ArrayList<Point>();
for (int i = getMinArea(); i <= getMaxArea(); ++i) {
factors = calcFactors(i);
for (int j = 0; j < factors.size(); ++j) {
possibleAreas.add(new Point(factors.get(j).x, factors.get(j).y));
}
}
return possibleAreas;
}
Calculating getMaxArea()
every time through the loop is silly. Also, you set factors
to new ArrayList<Point>()
at the top of the function, and then immediately throw away that value by assigning it a new value inside the loop. So at the bare minimum, I'd expect
private ArrayList<Point> calcPossibleAreas() {
ArrayList<Point> possibleAreas = new ArrayList<Point>();
int maxArea = getMaxArea();
for (int i = getMinArea(); i <= maxArea; ++i) {
ArrayList<Point> factors = calcFactors(i);
for (int j = 0; j < factors.size(); ++j) {
possibleAreas.add(factors.get(j));
}
}
return possibleAreas;
}
And then (AFAIK) you can use Java 5's for
-each loop:
private ArrayList<Point> calcPossibleAreas() {
ArrayList<Point> possibleAreas = new ArrayList<Point>();
int maxArea = getMaxArea();
for (int i = getMinArea(); i <= maxArea; ++i) {
for (Point factor : calcFactors(i)) {
possibleAreas.add(factor);
}
}
return possibleAreas;
}
But all that calcFactors
is expensive; and you wind up with a lot of 2xN rectangles that can't possibly be filled. So I would rather write it like this:
private ArrayList<Point> calcPossibleAreas() {
ArrayList<Point> possibleAreas = new ArrayList<Point>();
int minWidth = 0;
int maxWidth = 0;
int minHeight = 0;
int maxHeight = 0;
int minArea = 0;
for (Rectangle r : rectangleList) {
minWidth = Math.max(minWidth, r.width);
minHeight = Math.max(minHeight, r.height);
maxWidth += r.width;
maxHeight += r.height;
minArea += r.width * r.height;
}
int maxArea = Math.min(maxWidth * minHeight, minWidth * maxHeight);
for (int x = minWidth; x <= maxWidth; ++x) {
for (int y = minHeight; y <= maxHeight; ++y) {
if (minArea <= x * y && x * y <= maxArea) {
possibleAreas.add(new Point(x, y));
}
}
}
// Now sort possibleAreas so we'll try the smaller rectangles first.
Collections.sort(possibleAreas, new Comparator<Point>() {
@Override
public int compare(Point lhs, Point rhs) {
int la = (lhs.x * lhs.y), ra = (rhs.x * rhs.y);
return (la < ra) ? -1 : (la > ra);
}
});
}
Of course, calcPossibleAreas()
is just a preliminary step that will be very fast compared to placeRectangles()
. So Amdahl's Law says that you (and I ;)) should spend time optimizing placeRectangles()
rather than calcPossibleAreas()
. I would recommend looking at some way to eliminate the O(w*h)
writes to field
— is there some way you can express "all these positions are filled" without actually doing the O(w*h)
writes? Vice versa, is there some way you can test "is this a valid placement for my current rectangle" without doing O(w*h)
reads?
Rather than looking for places to put each rectangle, it might be better to look for ways to fill each point in the target. Pretend you have your set of rectangles, plus just enough "spare" 1x1 rectangles to fill up the empty spaces. If you try to fill all the points in the target, working downward from the upper left corner, then you have to try each rectangle in only one position — and you can skip rectangles that are too wide or tall to fit — and if none of your rectangles fit, and you're out of spare 1x1s, then you know it's time to backtrack. (This is essentially how Dancing Links would do it.)
answered 2 days ago
Quuxplusone
11.4k11959
11.4k11959
add a comment |
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210711%2frectangle-packing-in-smallest-possible-area%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Change your algortihm to ijcai.org/Proceedings/09/Papers/092.pdf
– RobAu
yesterday