168 lines
5.2 KiB
Text
168 lines
5.2 KiB
Text
---
|
|
id: rect-geo
|
|
title: "Rectangle Geometry"
|
|
author: Darren Yao, Michael Cao, Benjamin Qi
|
|
description: "Geometry problems on USACO Bronze are usually quite simple and limited to intersections and unions of squares or rectangles."
|
|
frequency: 2
|
|
---
|
|
import { Problem } from "../models";
|
|
|
|
export const metadata = {
|
|
problems: {
|
|
general: [
|
|
new Problem("Bronze", "Square Pasture", "663", "Intro", 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."),
|
|
]
|
|
}
|
|
};
|
|
|
|
|
|
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](http://usaco.org/index.php?page=viewproblem2&cpid=759)
|
|
|
|
### 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">
|
|
|
|
```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";
|
|
}
|
|
```
|
|
</spoiler>
|
|
|
|
Of course, this wouldn't suffice if the coordinates were up to $10^9$.
|
|
|
|
### Rectangle Class (Java)
|
|
|
|
A useful class in `Java` for dealing with rectangle geometry problems (though probably overkill) is the built-in [`Rectangle`](https://docs.oracle.com/javase/8/docs/api/java/awt/Rectangle.html) class. 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.
|
|
|
|
- `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">
|
|
|
|
```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.getWidth() <= 0 || r.getHeight() <= 0){
|
|
return 0;
|
|
}
|
|
return (long)r.getHeight() * (long)r.getWidth();
|
|
}
|
|
}
|
|
```
|
|
</spoiler>
|
|
|
|
### Rectangle Class (C++)
|
|
|
|
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!).
|
|
|
|
<spoiler title="C++ Solution">
|
|
|
|
```cpp
|
|
#include <iostream>
|
|
#include <fstream>
|
|
using namespace std;
|
|
|
|
struct Rect{
|
|
int x1, y1, x2, y2;
|
|
};
|
|
|
|
int area(Rect r){
|
|
return (r.y2 - r.y1) * (r.x2 - r.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 << area(a) + area(b) - intersect(a, t) - intersect(b, t);
|
|
}
|
|
|
|
```
|
|
</spoiler>
|
|
|
|
## Problems
|
|
|
|
<problems-list problems={metadata.problems.general} />
|