题目链接:POJ 1066
Description
Input
Output
Sample Input
7
20 0 37 100
40 0 76 100
85 0 0 75
100 90 0 90
0 71 100 61
0 14 100 38
100 47 47 100
54.5 55.4
Sample Output
Number of doors = 2
Source
East Central North America 1999
Solution
题意
给定 \(n\) 条线段,代表围墙,最外层为 \(100 \times 100\) 的正方形围墙。给定宝藏的坐标,求从外面进去拿到宝藏最少要穿过几堵墙。
思路
枚举正方形边上的所有端点与宝藏构成的线段,与多少堵墙相交,相交最少的即为答案。
线段 \(A\) 与线段 \(B\) 相交的判断:\(A\) 的两个端点在线段 \(B\) 的两边且线段 \(B\) 的两个端点在线段 \(A\) 的两边。
Code
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
typedef double db;
const db eps = 1e-8;
const int inf = 0x3f3f3f3f;
inline int dcmp(db x) {
if(fabs(x) < eps) return 0;
return x > 0? 1: -1;
}
class Point {
public:
double x, y;
Point(double x = 0, double y = 0) : x(x), y(y) {}
void input() {
scanf("%lf%lf", &x, &y);
}
bool operator<(const Point &a) const {
return (!dcmp(x - a.x))? dcmp(y - a.y) < 0: x < a.x;
}
bool operator==(const Point &a) const {
return dcmp(x - a.x) == 0 && dcmp(y - a.y) == 0;
}
Point operator+(const Point a) {
return Point(x + a.x, y + a.y);
}
Point operator-(const Point a) {
return Point(x - a.x, y - a.y);
}
Point operator*(double p) {
return Point(x * p, y * p);
}
Point operator/(double p) {
return Point(x / p, y / p);
}
db dot(const Point a) {
return x * a.x + y * a.y;
}
db cross(const Point a) {
return x * a.y - y * a.x;
}
};
class Line {
public:
Point s, e;
db angle;
Line() {}
Line(Point s, Point e) : s(s), e(e) {}
inline void input() {
scanf("%lf%lf%lf%lf", &s.x, &s.y, &e.x, &e.y);
}
bool operator<(const Line &a) const {
Line l = a;
if(dcmp(angle - l.angle) == 0) {
return l.toLeftTest(s) == 1;
}
return angle < l.angle;
}
int toLeftTest(Point p) {
if((e - s).cross(p - s) > 0) return 1;
else if((e - s).cross(p - s) < 0) return -1;
return 0;
}
int segcrossseg(Line l) {
if(l.toLeftTest(s) * l.toLeftTest(e) == -1 && toLeftTest(l.s) * toLeftTest(l.e) == -1) {
return 1;
} else {
return 0;
}
}
Point crosspoint(Line l) {
double a1 = (l.e - l.s).cross(s - l.s);
double a2 = (l.e - l.s).cross(e - l.s);
double x = (s.x * a2 - e.x * a1) / (a2 - a1);
double y = (s.y * a2 - e.y * a1) / (a2 - a1);
if(dcmp(x) == 0) x = 0;
if(dcmp(y) == 0) y = 0;
return Point(x, y);
}
};
Line l[100];
Point tar;
int n;
int f(Line l1) {
int sum = 0;
for(int i = 0; i < n; ++i) {
if(l[i].segcrossseg(l1)) {
++sum;
}
}
return sum;
}
int main() {
scanf("%d", &n);
for(int i = 0; i < n; ++i) {
l[i].input();
}
tar.input();
int ans = inf;
for(int i = 0; i < n; ++i) {
Line l1 = Line(l[i].s, tar);
Line l2 = Line(l[i].e, tar);
int cnt1 = 0, cnt2 = 0;
for(int j = 0; j < n; ++j) {
if(i == j) continue;
if(l[j].segcrossseg(l1)) {
++cnt1;
}
if(l[j].segcrossseg(l2)) {
++cnt2;
}
}
ans = min(ans, min(cnt1, cnt2));
}
Point tmp = Point(0, 0);
ans = min(ans, f(Line(tmp, tar)));
tmp = Point(0, 100);
ans = min(ans, f(Line(tmp, tar)));
tmp = Point(100, 0);
ans = min(ans, f(Line(tmp, tar)));
tmp = Point(100, 100);
ans = min(ans, f(Line(tmp, tar)));
printf("Number of doors = %d\n", ans + 1);
return 0;
}