This repository has been archived on 2022-06-22. You can view files and clone it, but cannot push or open issues or pull requests.
usaco-guide/content/2_Bronze/Rect_Geo.mdx
2020-07-20 14:07:42 -07:00

214 lines
6.7 KiB
Text

---
id: rect-geo
title: "Rectangle Geometry"
author: Darren Yao, Michael Cao, Benjamin Qi
description: "Simple geometry problems in the Bronze division and library implementations to help you solve them easily."
frequency: 2
---
import { Problem } from "../models";
export const problems = {
blocked: [
new Problem("Bronze", "Blocked Billboard", "759", "Easy", false, ["rect"]),
],
general: [
new Problem("Bronze", "Square Pasture", "663", "Very Easy", false, ["rect"]),
new Problem("Bronze", "Blocked Billboard II", "783", "Easy", false, ["rect"]),
new Problem("CF", "Div. 3 C - White Sheet", "contest/1216/problem/C", "Normal", false, ["rect"],"See this code (TODO; codeforces is down) for a nice implementation using the Java Rectangle class."),
]
};
<Resources>
<Resource source="IUSACO" title="7.1 - Rectangle Geometry">module is based off this</Resource>
</Resources>
<br/>
Most only include two or three squares or rectangles, in which case you can simply draw out cases on paper. This should logically lead to a solution.
## Example: Blocked Billboard
<Problems problems={problems.blocked} />
### Naive Solution
Since all coordinates are in the range $[-1000,1000]$, we can simply go through each of the $2000^2$ possible visible squares and check which ones are visible using nested for loops.
<Spoiler title="Nested Loops">
<LanguageSection>
<CPPSection>
```cpp
#include <bits/stdc++.h>
using namespace std;
bool ok[2000][2000];
int main() {
freopen("billboard.in","r",stdin);
freopen("billboard.out","w",stdout);
for (int i = 0; i < 3; ++i) {
int x1, y1, x2, y2; cin >> x1 >> y1 >> x2 >> y2;
x1 += 1000, y1 += 1000, x2 += 1000, y2 += 1000;
for (int x = x1; x < x2; ++x)
for (int y = y1; y < y2; ++y) {
if (i < 2) ok[x][y] = 1;
else ok[x][y] = 0;
}
}
int ans = 0;
for (int x = 0; x < 2000; ++x)
for (int y = 0; y < 2000; ++y)
ans += ok[x][y];
cout << ans << "\n";
}
```
</CPPSection>
</LanguageSection>
</Spoiler>
Of course, this wouldn't suffice if the coordinates were up to $10^9$.
### Rectangle Class
A useful class in Java for dealing with rectangle geometry problems (though definitely overkill) is the built-in [`Rectangle`](https://docs.oracle.com/javase/8/docs/api/java/awt/Rectangle.html) class.
<LanguageSection>
<JavaSection>
To create a new rectangle, use the following constructor:
```java
// creates a rectangle with upper-left corner at (x,y) with a specified width and height
Rectangle newRect = new Rectangle(x, y, width, height);
```
The `Rectangle` class supports numerous useful methods, including the following:
- `firstRect.intersects(secondRect)` checks if two rectangles intersect.
- `firstRect.union(secondRect)` returns a rectangle representing the union of two rectangles.
- `firstRect.contains(x, y)` checks whether the integer point $(x,y)$ exists in firstRect.
- `firstRect.intersection(secondRect)` returns a rectangle representing the intersection of two rectangles.
- what happens when intersection is empty?
This class can often lessen the implementation needed in a lot of bronze problems and CodeForces problems.
For example, here is a nice implementation of the problem ([editorial](http://www.usaco.org/current/data/sol_billboard_bronze_dec17.html)).
<Spoiler title="Java Solution With Built-in Rectangle Class">
```java
import java.awt.Rectangle; //needed to use Rectangle class
import java.io.*;
import java.util.*;
public class blockedBillboard {
public static void main(String[] args) throws IOException{
Scanner sc = new Scanner(new File("billboard.in"));
PrintWriter pw = new PrintWriter(new FileWriter("billboard.out"));
int x1, y1, x2, y2;
// the top left point is (0,0), so you need to do -y2
x1 = sc.nextInt(); y1 = sc.nextInt(); x2 = sc.nextInt(); y2 = sc.nextInt();
Rectangle firstRect = new Rectangle(x1, -y2, x2-x1, y2-y1);
x1 = sc.nextInt(); y1 = sc.nextInt(); x2 = sc.nextInt(); y2 = sc.nextInt();
Rectangle secondRect = new Rectangle(x1, -y2, x2-x1, y2-y1);
x1 = sc.nextInt(); y1 = sc.nextInt(); x2 = sc.nextInt(); y2 = sc.nextInt();
Rectangle truck = new Rectangle(x1, -y2, x2-x1, y2-y1);
long firstIntersect = getArea(firstRect.intersection(truck));
long secondIntersect = getArea(secondRect.intersection(truck));
pw.println(getArea(firstRect)+getArea(secondRect)
- firstIntersect - secondIntersect);
pw.close();
}
public static long getArea(Rectangle r){
if (r.isEmpty()) return 0;
return (long)r.getHeight()*(long)r.getWidth();
}
}
```
</Spoiler>
<Spoiler title="Java Solution Without Built-in Rectangle Class">
```java
import java.io.*;
import java.util.*;
class Rect {
int x1, y1, x2, y2;
Rect() {}
int area() { return (y2-y1)*(x2-x1); }
}
public class blockedBillboard {
public static void main (String[] args) throws IOException{
Scanner sc = new Scanner(new File("billboard.in"));
PrintWriter pw = new PrintWriter(new FileWriter("billboard.out"));
Rect a = new Rect(), b = new Rect(), t = new Rect();
int x1, y1, x2, y2;
a.x1 = sc.nextInt(); a.y1 = sc.nextInt(); a.x2 = sc.nextInt(); a.y2 = sc.nextInt();
b.x1 = sc.nextInt(); b.y1 = sc.nextInt(); b.x2 = sc.nextInt(); b.y2 = sc.nextInt();
t.x1 = sc.nextInt(); t.y1 = sc.nextInt(); t.x2 = sc.nextInt(); t.y2 = sc.nextInt();
pw.println(a.area()+b.area()-intersect(a, t)-intersect(b, t));
pw.close();
}
static int intersect(Rect p, Rect q) {
int xOverlap = Math.max(0, Math.min(p.x2, q.x2) - Math.max(p.x1, q.x1));
int yOverlap = Math.max(0, Math.min(p.y2, q.y2) - Math.max(p.y1, q.y1));
return xOverlap * yOverlap;
}
}
```
</Spoiler>
</JavaSection>
<CPPSection>
Unfortunately, C++ doesn't have a built in rectangle class, so you need to write the functions yourself. Here is the solution to Blocked Billboard written in C++ (thanks, Brian Dean!). A C++ [`struct`](http://www.cplusplus.com/doc/tutorial/structures/) is the same as a C++ `class` but all members are `public` rather than `private` by default.
<Spoiler title="C++ Solution">
```cpp
#include <bits/stdc++.h>
using namespace std;
struct Rect {
int x1,y1,x2,y2;
int area() { return (y2-y1)*(x2-x1); }
};
int intersect(Rect p, Rect q){
int xOverlap = max(0,min(p.x2,q.x2)-max(p.x1,q.x1));
int yOverlap = max(0,min(p.y2,q.y2)-max(p.y1,q.y1));
return xOverlap*yOverlap;
}
int main(){
ifstream cin ("billboard.in");
ofstream cout ("billboard.out");
Rect a, b, t; // billboards a, b, and the truck
cin >> a.x1 >> a.y1 >> a.x2 >> a.y2;
cin >> b.x1 >> b.y1 >> b.x2 >> b.y2;
cin >> t.x1 >> t.y1 >> t.x2 >> t.y2;
cout << a.area()+b.area()-intersect(a,t)-intersect(b,t) << endl;
}
```
</Spoiler>
</CPPSection>
</LanguageSection>
## Problems
<Problems problems={problems.general} />