A
[link](2318 – TOYS (poj.org))
题意
给你一些木板隔开一个盒子,然后给你一些玩具的坐标,最后从前往后输出每个隔间的玩具数目。
题解
首先对于输入的木板我们给最右边在加上一个板子,方便后面操作。我们可以用cross来判断点和直线的关系,点在直线的左边cross>0,右边cross<0。进一步来看假设某个点p位于第二个隔间,对于这个点来说他一定在这个隔间右边所有边的左边,这个隔间左边所有边的右边,因此发现具有二段性,所以可以用二分来查找就可以了。
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <bitset>
#include <cmath>
#include <stack>
#include <iomanip>
#include <deque>
#include <sstream>
#define x first
#define y second
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1);
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
PDD U[N], D[N];
int res[N];
PDD operator -(PDD a, PDD b) {return {a.x - b.x, a.y - b.y};}
double cross(PDD a, PDD b) {return a.x * b.y - a.y * b.x;}
double area(PDD a, PDD b, PDD c) {return cross(b - a, c - a);}
int main() {
// ios::sync_with_stdio(false), cin.tie(0);
bool ok = false;
while (scanf("%d", &n), n) {
double x1, y1, x2, y2;
scanf("%d%lf%lf%lf%lf", &m, &x1, &y1, &x2, &y2);
for (int i = 0; i <= n; i ++ ) res[i] = 0;
for (int i = 0; i < n; i ++ ) {
double u, d; scanf("%lf%lf", &u, &d);
U[i] = {u, y1}, D[i] = {d, y2};
}
U[n] = {x2, y1}, D[n] = {x2, y2};
if (!ok) ok = true;
else puts("");
while (m --) {
PDD p; scanf("%lf%lf", &p.x, &p.y);
int l = 0, r = n;
while (l < r) {
int mid = l + r >> 1;
if (area(D[mid], U[mid], p) > 0) r = mid;
else l = mid + 1;
}
res[l] ++;
}
for (int i = 0; i <= n; i ++ ) printf("%d: %d\n", i, res[i]);
}
return 0;
}
B
[link](2398 – Toy Storage (poj.org))
题意
同 A A A差不多,只不过给的隔板是无序的。
题解
我们只需要给直线排个先后顺序,剩下的和A题大同小异,注意一下输出即可。
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <bitset>
#include <cmath>
#include <stack>
#include <iomanip>
#include <deque>
#include <sstream>
#define x first
#define y second
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1);
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
struct Line {
PDD st, ed;
}line[N];
int res[N];
int dcmp(double x, double y) {
if (fabs(x - y) < eps) return 0;
if (x < y) return -1;
return 1;
}
PDD operator -(PDD a, PDD b) {return {a.x - b.x, a.y - b.y};}
double cross(PDD a, PDD b) {return a.x * b.y - a.y * b.x;}
double area(PDD a, PDD b, PDD c) {return cross(b - a, c - a);}
bool cmp(Line a, Line b) {
return max(a.st.x, a.ed.x) < max(b.st.x, b.ed.x);
}
int main() {
while (scanf("%d", &n), n) {
double x1, y1, x2, y2;
scanf("%d%lf%lf%lf%lf", &m, &x1, &y1, &x2, &y2);
for (int i = 0; i <= n; i ++ ) res[i] = 0;
for (int i = 0; i < n; i ++ ) {
PDD t; scanf("%lf%lf", &t.x, &t.y);
line[i] = {{t.x, y1}, {t.y, y2}};
}
line[n] = {{x2, y1}, {x2, y2}};
sort(line, line + n + 1, cmp);
while (m --) {
PDD p; scanf("%lf%lf", &p.x, &p.y);
int l = 0, r = n;
while (l < r) {
int mid = l + r >> 1;
if (area(line[mid].ed, line[mid].st, p) > 0) r = mid;
else l = mid + 1;
}
res[l] ++;
}
map<int, int> mp;
vector<int> ans;
for (int i = 0; i <= n; i ++ )
if (!mp[res[i]] && res[i]) {
mp[res[i]] ++;
ans.push_back(res[i]);
}
else mp[res[i]] ++;
sort(ans.begin(), ans.end());
puts("Box");
for (int i = 0; i < ans.size(); i ++ ) printf("%d: %d\n", ans[i], mp[ans[i]]);
}
return 0;
}
C
[Link](3304 – Segments (poj.org))
题意
给你一些线段,问你是是否存在一条直线使得这n条线段投影到该直线上,所有的投影线段至少有一个公共点。
题解
可以将转化为找是否存在一条直线和所有的线段都相交。因为如果存在一个直线 l l l满足,做一条直线 m m m与 l l l垂直,那么所有的线段投影到 m m m上一定都和这两条直线的垂足相交。
考虑怎么枚举直线,我们发现所有可能的直线,至少从与一个线段有交点开始。所有我们可以先找过一个线段的直线,然后旋转他(等价变换)。我们把这个直线的定点设为该线段的一个端点,然后旋转,因为要满足和所有的线段相交,所以旋转的时候肯定无法超过另一个线段的端点,所有我们可枚举的直线可以卡在不同线段的端点的连线里。
就可以 O ( n 2 ) O(n^2) O(n2)的枚举直线, O ( n ) O(n) O(n)的去判断是否和所有的线段有交点。
如何判断线段和直线有交点?
判断线段的两端点是否在直线的两边即可,也就是两边的cross异号。
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <bitset>
#include <cmath>
#include <stack>
#include <iomanip>
#include <deque>
#include <sstream>
#define x first
#define y second
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1);
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
struct LIne {
PDD st, ed;
}line[N];
PDD q[N];
int sgn(double x) {
if (fabs(x) < eps) return 0;
if (x < 0) return -1;
return 1;
}
int dcmp(double x, double y) {
if (fabs(x - y) < eps) return 0;
if (x < y) return -1;
return 1;
}
PDD operator -(PDD a, PDD b) {
return {a.x - b.x, a.y - b.y};
}
double cross(PDD a, PDD b) {
return a.x * b.y - a.y * b.x;
}
double area(PDD a, PDD b, PDD c) {
return cross(b - a, c - a);
}
bool check() {
for (int i = 0; i < n * 2; i ++ ) {
for (int j = i + 1; j < n * 2; j ++ ) {
bool ok = true;
if (!dcmp(q[i].x, q[j].x) && !dcmp(q[i].y, q[j].y)) continue;
for (int k = 0; k < n; k ++ )
if (sgn(area(q[i], q[j], line[k].st)) * sgn(area(q[i], q[j], line[k].ed)) > 0) {
ok = false;
break;
}
if (ok) return true;
}
}
return false;
}
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T;
cin >> T;
while (T -- ) {
cin >> n;
for (int i = 0, k = 0; i < n; i ++ ) {
double x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
q[k ++] = {x1, y1}, q[k ++] = {x2, y2};
line[i] = {{x1, y1}, {x2, y2}};
}
if (check()) puts("Yes!");
else puts("No!");
}
return 0;
}
D
[Link](1269 – Intersecting Lines (poj.org))
题意
给出两条直线,判断相交、平行、重合
题解
对于直线来说cross不为零一定相交。求交点可以用公式推,也可以用相似三角形。
cross为0则为平行或重合,任选一条直线的一个边与另一条直线的两个端点做cross,为0重合,不为零平行。
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <stack>
#include <iomanip>
#include <deque>
#include <cmath>
#include <sstream>
#define x first
#define y second
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
struct Line {
PDD st, ed;
}line[N];
int sgn(double x) {
if (fabs(x) < eps) return 0;
if (x < 0) return -1;
return 1;
}
int dcmp(double x, double y) {
if (fabs(x - y) < eps) return 0;
if (x < y) return -1;
return 1;
}
double operator *(PDD a, PDD b) {
return a.x * b.y - a.y * b.x;
}
PDD operator *(PDD a, double t) {
a.x *= t, a.y *= t;
return a;
}
PDD operator /(PDD a, double t) {
a.x /= t, a.y /= t;
//return {a.x / t, a.y / t};
return a;
}
PDD operator +(PDD a, PDD b) {
a.x += b.x, a.y += b.y;
//return {a.x + b.x, a.y + b.y};
return a;
}
PDD operator -(PDD a, PDD b) {
a.x -= b.x, a.y -= b.y;
//return {a.x - b.x, a.y - b.y};
return a;
}
PDD get_line_intersection(PDD p, PDD v, PDD q, PDD w) {
PDD u = p - q;
double t = w * u / (v * w);
return p + v * t;
}
int main() {
// ios::sync_with_stdio(false), cin.tie(0);
int T;
cin >> T;
printf("INTERSECTING LINES OUTPUT\n");
while (T -- ) {
Line a, b;
cin >> a.st.x >> a.st.y >> a.ed.x >> a.ed.y;
cin >> b.st.x >> b.st.y >> b.ed.x >> b.ed.y;
if (!sgn((a.ed - a.st) * (b.ed - b.st))) {
if (!sgn((a.st - b.st) * (a.ed - b.st))) {
puts("LINE");
}
else puts("NONE");
}
else {
PDD t = get_line_intersection(a.st, a.ed - a.st, b.st, b.ed - b.st);
printf("POINT %.2lf %.2lf\n", t.x, t.y);
}
}
printf("END OF OUTPUT\n");
return 0;
}
E
[Link](1556 – The Doors (poj.org))
题意
给你一个边长为10的正方形,给你n个输入,每个输入给五个坐标 x 1 , y 1 , y 2 , y 3 , y 4 x1,y1,y2,y3,y4 x1,y1,y2,y3,y4,代表 x 1 x1 x1的位置有 [ 0 , y 1 ] , [ y 2 , y 3 ] , [ y 4 , 10 ] [0,y1],[y2,y3],[y4,10] [0,y1],[y2,y3],[y4,10]三堵墙。然后问你从 ( 0 , 5 ) − > ( 10 , 5 ) (0,5)->(10,5) (0,5)−>(10,5)的最短路程。
题解
首先两点之间线段最短,我们一定是从某个点沿直线走到另一个点。因此存下所有的有效的点,和所有的墙,考虑用邻接矩阵存任意两个点之间的距离,我们枚举任意两个有效点,看是否和墙有交点,如果有边权就是INF,没有就是dist(line)。
因为点和线的都是从前往后按顺序给出的且点是线的二倍,所以第 i i i个点对应的线应该是(i + 1) / 2。所以i、j这个边需要判断的墙就在(l + 1) / 2 + 1, (r + 1) / 2 - 1这个范围内。
最后建完图跑一遍dijkstra即可。
对于线段相交
规范相交:有且仅有一个不为端点的交点
**非规范相交:**相交且交点为端点或部分重合
**不相交:**无交点
对于两个线段是否相交可以用跨立交实验,如果一个线段和另一个线段的两个端点做cross异号,则则证明另一个线段一定在这个线段的两边(但不一定相交),再交换做一次如果也是异号就一定规范相交。如果有一个为零,且有一个线段的一个端点和另一个线段的端点做dot为负,则为非规范相交,否则为不相交。
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <bitset>
#include <cmath>
#include <stack>
#include <iomanip>
#include <deque>
#include <sstream>
#define x first
#define y second
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1010, M = 2 * N, mod = 1e9 + 7;
const double eps = 1e-8, INF = 999999999.0;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int n, m, k;
struct Line {
PDD st, ed;
}line[N];
PDD p[N];
int cnt1, cnt2;
double g[N][N];
double dist[N];
bool st[N];
int sgn(double x) {
if (fabs(x) < eps) return 0;
if (x < 0) return -1;
return 1;
}
int dcmp(double x, double y) {
if (fabs(x - y) < eps) return 0;
if (x < y) return -1;
return 1;
}
PDD operator +(PDD a, PDD b) {
a.x += b.x, a.y += b.y;
//return {a.x + b.x, a.y + b.y};
return a;
}
PDD operator -(PDD a, PDD b) {
a.x -= b.x, a.y -= b.y;
//return {a.x - b.x, a.y - b.y};
return a;
}
PDD operator *(PDD a, double t) {
a.x *= t, a.y *= t;
// return {a.x * t, a.y * t};
return a;
}
PDD operator /(PDD a, double t) {
a.x /= t, a.y /= t;
// return {a.x / t, a.y / t};
return a;
}
double operator *(PDD a, PDD b) {
return a.x * b.y - a.y * b.x;
}
double operator &(PDD a, PDD b) {
return a.x * b.x + a.y * b.y;
}
double get_len(PDD a) {
return sqrt(a & a);
}
double cross(PDD a, PDD b, PDD c) {
return (b - a) * (c - a);
}
bool segment_intersection(PDD a1, PDD a2, PDD b1, PDD b2) {
double c1 = (a2 - a1) * (b1 - a1), c2 = (a2 - a1) * (b2 - a1);
double c3 = (b2 - b1) * (a1 - b1), c4 = (b2 - b1) * (a2 - b1);
return sgn(c1) * sgn(c2) < 0 && sgn(c3) * sgn(c4) < 0;
// return (cross(a1, b1, a2) * cross(a1, a2, b2) > 0) && (cross(b1, a1, b2) * cross(b1, b2, a2) > 0);
}
double dijkstra() {
for (int i = 0; i < cnt1; i ++ ) dist[i] = INF, st[i] = false;
dist[0] = 0;
for (int i = 0; i < cnt1; i ++ ) {
int t = -1;
for (int j = 0; j < cnt1; j ++ )
if (!st[j] && (t == -1 || dist[t] > dist[j])) t = j;
for (int j = 0; j < cnt1; j ++ )
dist[j] = min(dist[j], dist[t] + g[t][j]);
st[t] = true;
}
return dist[cnt1 - 1];
}
int main() {
while (cin >> n, ~n) {
cnt1 = 0, cnt2 = 0;
p[cnt1].x = 0, p[cnt1].y = 5, cnt1 ++;
// p[cnt1 ++] = {0, 5};
for (int i = 0; i < n; i ++ ) {
double x, y1, y2, y3, y4;
cin >> x >> y1 >> y2 >> y3 >> y4;
// p[cnt1 ++] = {x, 0}, p[cnt1 ++] = {x, y1}, line[cnt2 ++] = {p[cnt1 - 2], p[cnt1 - 1]};
p[cnt1].x = x, p[cnt1].y = 0, cnt1 ++, p[cnt1].x = x, p[cnt1].y = y1, cnt1 ++, line[cnt2].st = p[cnt1 - 2], line[cnt2].ed = p[cnt1 - 1], cnt2 ++;
p[cnt1].x = x, p[cnt1].y = y2, cnt1 ++, p[cnt1].x = x, p[cnt1].y = y3, cnt1 ++, line[cnt2].st = p[cnt1 - 2], line[cnt2].ed = p[cnt1 - 1], cnt2 ++;
p[cnt1].x = x, p[cnt1].y = y4, cnt1 ++, p[cnt1].x = x, p[cnt1].y = 10, cnt1 ++, line[cnt2].st = p[cnt1 - 2], line[cnt2].ed = p[cnt1 - 1], cnt2 ++;
// p[cnt1 ++] = {x, y2},p[cnt1 ++] = {x, y3}, line[cnt2 ++] = {p[cnt1 - 2], p[cnt1 - 1]};
// p[cnt1 ++] = {x, y4}, p[cnt1 ++] = {x, 10}, line[cnt2 ++] = {p[cnt1 - 2], p[cnt1 - 1]};
}
// p[cnt1 ++] = {10, 5};
p[cnt1].x = 10, p[cnt1].y = 5, cnt1 ++;
for (int i = 0; i < cnt1; i ++ )
for (int j = i; j < cnt1; j ++ ) {
if (i == j) {
g[i][j] = g[j][i] = 0;
continue;
}
int lf = (i + 1) / 2, rt = (j + 1) / 2;
bool ok = false;
for (int k = lf + 1; k < rt; k ++ )
if(segment_intersection(p[i], p[j], line[k].st, line[k].ed)) {
ok = true;
break;
}
if (ok) g[i][j] = g[j][i] = INF;
else g[i][j] = g[j][i] = get_len(p[i] - p[j]);
}
printf("%.2lf\n", dijkstra());
}
return 0;
}
F
[link](2653 – Pick-up sticks (poj.org))
题意
给n个线段,后给的如果和前面给的有交点就会把前面那个覆盖掉,问最后有哪些线段没有被覆盖。
题解
按顺序模拟即刻,每一个和前面的暴力枚举判断,相交就把前面的删掉。
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <bitset>
#include <cmath>
#include <stack>
#include <iomanip>
#include <deque>
#include <sstream>
#define x first
#define y second
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
struct Line {
PDD st, ed;
}line[N];
bool st[N];
int sgn(double x) {
if (fabs(x) < eps) return 0;
if (x < 0) return -1;
return 1;
}
PDD operator +(PDD a, PDD b) {
a.x += b.x, a.y += b.y;
return a;
}
PDD operator -(PDD a, PDD b) {
a.x -= b.x, a.y -= b.y;
return a;
}
PDD operator /(PDD a, double t) {
a.x /= t, a.y /= t;
return a;
}
double operator *(PDD a, PDD b) {
return a.x * b.y - a.y * b.x;
}
bool segment_intersection(PDD a1, PDD a2, PDD b1, PDD b2) {
double c1 = (a2 - a1) * (b1 - a1), c2 = (a2 - a1) * (b2 - a1);
double c3 = (b2 - b1) * (a1 - b1), c4 = (b2 - b1) * (a2 - b1);
return sgn(c1) * sgn(c2) <= 0 && sgn(c3) * sgn(c4) <= 0;
}
int main() {
ios::sync_with_stdio(false), cin.tie(0);
while (cin >> n, n) {
for (int i = 1; i <= n; i ++ ) cin >> line[i].st.x >> line[i].st.y >> line[i].ed.x >> line[i].ed.y;
vector<int> res;
res.push_back(1);
for (int i = 2; i <= n; i ++ ) {
vector<int> t;
for (int x = 0; x < res.size(); x ++ ) {
if (!segment_intersection(line[i].st, line[i].ed, line[res[x]].st, line[res[x]].ed)) t.push_back(res[x]);
}
res = t;
res.push_back(i);
}
cout << "Top sticks:";
for (int i = 0; i < res.size(); i ++ ) {
cout << " " << res[i];
cout << (i == res.size() - 1 ? "." : ",");
}
cout << endl;
}
return 0;
}
G
[link](1066 – Treasure Hunt (poj.org))
题意
一个正方形的墓葬内有n堵墙,每堵墙的两个顶点都在正方形的边界上,现在这些墙将墓葬分割成了很多小空间,已知正方形内的一个点上存在宝藏,现在我们要在正方形的外面去得到宝藏,对于每个小空间,我们可以炸开它的任意一条边的中点,现在给出每堵墙的两个节点的坐标和宝藏的坐标,问如果要得到宝藏,需要炸的墙数最少是多少。
题解
与题C的转化思想相似最终答案一定是在两条线段的端点,因此只需要枚举正方形变上的点和目标点连一条线段,判断这条线段交多少条线段就是当前选择的最优解。注意要是规范相交,如果是当前选择的这个起点的线段不算在相交内,对于一开始进入正方形还要炸一次。
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <bitset>
#include <cmath>
#include <stack>
#include <iomanip>
#include <deque>
#include <sstream>
#define x first
#define y second
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
struct Line {
PDD st, ed;
}line[N];
int cnt;
PDD p[N], vis;
bool st[N];
int sgn(double x) {
if (fabs(x) < eps) return 0;
if (x < 0) return -1;
return 1;
}
PDD operator +(PDD a, PDD b) {
a.x += b.x, a.y += b.y;
return a;
}
PDD operator -(PDD a, PDD b) {
a.x -= b.x, a.y -= b.y;
return a;
}
PDD operator /(PDD a, double t) {
a.x /= t, a.y /= t;
return a;
}
double operator *(PDD a, PDD b) {
return a.x * b.y - a.y * b.x;
}
bool segment_intersection(PDD a1, PDD a2, PDD b1, PDD b2) {
double c1 = (a2 - a1) * (b1 - a1), c2 = (a2 - a1) * (b2 - a1);
double c3 = (b2 - b1) * (a1 - b1), c4 = (b2 - b1) * (a2 - b1);
return sgn(c1) * sgn(c2) < 0 && sgn(c3) * sgn(c4) < 0;
}
int main() {
ios::sync_with_stdio(false), cin.tie(0);
cin >> n;
for (int i = 0; i < n; i ++ ) {
cin >> line[i].st.x >> line[i].st.y >> line[i].ed.x >> line[i].ed.y;
p[cnt] = line[i].st, cnt ++, p[cnt] = line[i].ed, cnt ++;
}
cin >> vis.x >> vis.y;
int res = INF;
for (int i = 0; i < cnt; i ++ ) {
int sum = 0;
for (int j = 0; j < n; j ++ )
if (segment_intersection(p[i], vis, line[j].st, line[j].ed)) sum ++;
// cout << sum << endl;
res = min(res, sum);
}
if (n == 0) res = 0;
cout << "Number of doors = " << res + 1 << endl;
return 0;
}
H
[Link]([kuangbin带你飞]专题十三 基础计算几何 [Cloned] - Virtual Judge (vjudge.net))
题意
给你一个正方形和一个线段,判断线段和正方形是否有交点,正方形是实心的所以线在内部也算有交点。
题解
注意一开始给的坐标可能是无序的,所以要判断一下保证a是左上角c是右下角。然后先判断是否相交,在判断是否在正方形内部,可以看线段端点坐标和a、c两点的位置关系即可。
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <bitset>
#include <cmath>
#include <stack>
#include <iomanip>
#include <deque>
#include <sstream>
#define x first
#define y second
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = 3.14159, inf = 1e20;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int a[N];
int sgn(double x) {
if (fabs(x) < eps) return 0;
if (x < 0) return -1;
return 1;
}
int dcmp(double x, double y) {
if (fabs(x - y) < eps) return 0;
if (x < y) return -1;
return 1;
}
inline double sqr(double x) {
return x * x;
}
struct Point {
double x, y;
Point() {}
Point (double _x, double _y) {
x = _x, y = _y;
}
void input() {
scanf("%lf%lf", &x, &y);
}
void output() {
printf("%.2lf %.2lf", x, y);
}
bool operator ==(Point b) const{
return sgn(x - b.x) == 0 && sgn(y - b.y) == 0;
}
bool operator <(Point b) const{
return sgn(x - b.x) == 0 ? sgn(y - b.y) < 0 : x < b.x;
}
Point operator -(const Point &b) const{
return Point(x - b.x, y - b.y);
}
Point operator +(const Point &b) const{
return Point(x + b.x, y + b.y);
}
Point operator *(const double &t) const{
return Point(x * t, y * t);
}
Point operator /(const double &t) const{
return Point(x / t, y / t);
}
//cross
double operator ^(const Point &b) const{
return x * b.y - y * b.x;
}
// dot
double operator *(const Point &b) const{
return x * b.x + y * b.y;
}
double len() {
return hypot(x, y);
}
double len2() {
return x * x + y * y;
}
double distance(Point p) {
return hypot(x - p.x, y - p.y);
}
// pa pa 夹角
double rad(Point a, Point b) {
Point p = *this;
return fabs(atan2(fabs((a - p) ^ (b - p)), (a - p) * (b - p)));
}
// 转化为长度为r的向量
Point trunc(double r) {
double l = len();
if (!sgn(l)) return *this;
r /= l;
return Point(x * r, y * r);
}
//逆时针旋转90度
Point rotleft() {
return Point(-y, x);
}
//顺时针旋转90度
Point rotright() {
return Point(y, -x);
}
// 绕着p点逆时针旋转 rad度
Point rotate(Point p, double rad) {
Point v = (*this) - p;
double c = cos(rad), s = sin(rad);
return Point(p.x + v.x * c - v.y * s, p.y + v.x * s + v.y * c);
}
};
struct Line {
Point s, e;
Line() {}
Line(Point _s, Point _e) {
s = _s, e = _e;
}
// 根据一个点和倾斜角 angle 确定直线, 0<=angle< pis
Line(Point p, double angle) {
s = p;
if (sgn(angle - pi / 2) == 0) e = (s + Point(0, 1));
else e = (s + Point(1, tan(angle))); // 往上平移
}
//ax + by + c = 0;
Line(double a, double b, double c) {
if (!sgn(a)) {
s = Point(0, -c / b);
e = Point(1, -c / b);
}
else if (!sgn(b)) {
s = Point(-c / a, 0);
e = Point(-c / a, 1);
}
else {
s = Point(0, -c / b);
e = Point(1, (-c - a) / b);
}
}
bool operator ==(Line v) {
return (s == v.s) && (e == v.e);
}
void input() {
s.input(), e.input();
}
void adjust() {
if (e < s) swap(s, e);
}
// 线段长度
double length() {
return s.distance(e);
}
// 直线倾斜角 0<=angle<pi
double angle() {
double k = atan2(e.y - s.y, e.x - s.x);
if (sgn(k) < 0) k += pi;
if (sgn(k - pi) == 0) k -= pi;
return k;
}
// 点和线的关系 1.左边 2.右边 3.线上
int relation(Point p) {
int c = sgn((p - s) ^ (e - s));
if (c < 0) return 1;
else if (c > 0) return 2;
return 3;
}
//点在线段上
bool pointonseg(Point p) {
return sgn((p-s)^(e-s)) == 0 && sgn((s-p)*(e-p)) <= 0;
}
// 两直线平行
bool parallel(Line v) {
return sgn((e - s) ^ (v.e - v.s)) == 0;
}
// 两线段相交判断 2 规范相交 1 不规范相交 0 不相交
int segcrossseg(Line v) {
int d1 = sgn((e-s)^(v.s-s)), d2 = sgn((e-s)^(v.e-s));
int d3 = sgn((v.e-v.s)^(s-v.s)), d4 = sgn((v.e-v.s)^(e-v.s));
if ((d1^d2) == -2 && (d3^d4) == -2) return 2;
return (d1==0 && sgn((v.s-s)*(v.s-e))<=0) ||
(d2==0 && sgn((v.e-s)*(v.e-e))<=0) ||
(d3==0 && sgn((s-v.s)*(s-v.e))<=0) ||
(d4==0 && sgn((e-v.s)*(e-v.e))<=0);
}
// 直线和线段相交判断 2 规范相交 1 不规范相交 0 不相交 this line v seg
int linecorssseg(Line v) {
int d1 = sgn((e-s)^(v.s-s)), d2 = sgn((e-s)^(v.e-s));
if ((d1^d2) == -2) return 2;
return (!d1 || !d2);
}
// 两直线关系 0 平行 1 重合 2 相交
int linecrossline(Line v) {
if ((*this).parallel(v)) return v.relation(s) == 3;
return 2;
}
// 求两直线的交点,保证不平行和重合
Point crossPoint(Line v) {
double a1 = (v.e-v.s)^(s-v.s), a2 = (v.e-v.s)^(e-v.s);
return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1));
}
double dispointtoline(Point p) {
return fabs((e-s)^(p-s)) / length();
}
double dispointtoseg(Point p) {
if (sgn((e-s)*(p-s)) < 0 || sgn((e-s)*(p-e)) < 0) return min(p.distance(s), p.distance(e));
return dispointtoline(p);
}
// 返回线段和线段的距离,保证不能相交
double dissegtoseg(Line v) {
return min(min(dispointtoseg(v.s), dispointtoseg(v.e)),
min(v.dispointtoseg(s), v.dispointtoseg(e)));
}
// 返回点p在直线上的投影
Point lineprog(Point p) {
return s + (((e-s)*((e-s)*(p-s))/(e-s).len2()));
}
};
// 1111
int main() {
int T;
cin >> T;
while (T -- ) {
Line l; l.input();
Point a, b, c, d;
a.input(), c.input();
if (a.x > c.x) swap(a.x, c.x);
if (a.y < c.y) swap(a.y, c.y);
b.x = c.x, b.y = a.y;
d.x = a.x, d.y = c.y;
bool ok = false;
// cout << l.segcrossseg(Line(a, b)) << endl;
if (l.segcrossseg(Line(a, b)) || l.segcrossseg(Line(b, c)) || l.segcrossseg(Line(c, d)) || l.segcrossseg(Line(d, a))) ok = true;
if ((a.x <= l.s.x && c.x >= l.s.x && a.y >= l.s.y && c.y <= l.s.y) ||
(a.x <= l.e.x && c.x >= l.e.x && a.y >= l.e.y && c.y <= l.e.y)) ok = true;
// if((a.x<=l.s.x&&l.s.x<=c.x&&c.y<=l.s.y&&l.s.y<=a.y)||(a.x<=l.e.x&&l.e.x<=c.x&&c.y<=l.e.y&&l.e.y<=a.y)) ok = true;
cout << (ok ? "T" : "F") << endl;
}
return 0;
}
I
[link](1696 – Space Ant (stdu.edu.cn))
题意
给你一些食物的位置和一只蚂蚁,蚂蚁每次只能向偏左走,每次行走会留下足迹,蚂蚁不会再次经过足迹,蚂蚁一开始可以活着一天,每天需要吃一个食物才能继续存活下去,同一天只能吃一个食物,问蚂蚁最多可以活多少天和每天吃的是什么食物。
题解
我们一开始肯定是吃最靠左下的食物,然后吃完这个还会再吃新的位置的朝向的最靠左下的位置,因为我们每次选择的点都是剩下所有点里距离当前这个点最靠外且近的点,所以这样吃就可以把所有的食物都吃掉。
再进一步发现这样最靠外且靠近的就是以当前这个点为极点排序以后极角最小的点。因此我们每次对剩下的点以当前吃了的这个点为轴极角排序,然后取离得最近的点即可。
极角排序
选一个点为极点,以这个点为轴来排序,对于任意两个点极角小的cross极角大的应该大于0,如果极角相同距离极点近的排在前面。
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <bitset>
#include <cmath>
#include <stack>
#include <iomanip>
#include <deque>
#include <sstream>
#define x first
#define y second
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 10010, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = 3.14159, inf = 1e20;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int a[N];
int sgn(double x) {
if (fabs(x) < eps) return 0;
if (x < 0) return -1;
return 1;
}
int dcmp(double x, double y) {
if (fabs(x - y) < eps) return 0;
if (x < y) return -1;
return 1;
}
inline double sqr(double x) {
return x * x;
}
struct Point {
double x, y;
Point() {}
Point (double _x, double _y) {
x = _x, y = _y;
}
void input() {
scanf("%lf%lf", &x, &y);
}
void output() {
printf("%.2lf %.2lf", x, y);
}
bool operator ==(Point b) const{
return sgn(x - b.x) == 0 && sgn(y - b.y) == 0;
}
bool operator <(Point b) const{
return sgn(x - b.x) == 0 ? sgn(y - b.y) < 0 : x < b.x;
}
Point operator -(const Point &b) const{
return Point(x - b.x, y - b.y);
}
Point operator +(const Point &b) const{
return Point(x + b.x, y + b.y);
}
Point operator *(const double &t) const{
return Point(x * t, y * t);
}
Point operator /(const double &t) const{
return Point(x / t, y / t);
}
//cross
double operator ^(const Point &b) const{
return x * b.y - y * b.x;
}
// dot
double operator *(const Point &b) const{
return x * b.x + y * b.y;
}
double len() {
return hypot(x, y);
}
double len2() {
return x * x + y * y;
}
double distance(Point p) {
//return hypot(x - p.x, y - p.y);
return sqrt((p.x - x) * (p.x - x) + (p.y - y) * (p.y - y));
}
// pa pa 夹角
double rad(Point a, Point b) {
Point p = *this;
return fabs(atan2(fabs((a - p) ^ (b - p)), (a - p) * (b - p)));
}
// 转化为长度为r的向量
Point trunc(double r) {
double l = len();
if (!sgn(l)) return *this;
r /= l;
return Point(x * r, y * r);
}
//逆时针旋转90度
Point rotleft() {
return Point(-y, x);
}
//顺时针旋转90度
Point rotright() {
return Point(y, -x);
}
// 绕着p点逆时针旋转 rad度
Point rotate(Point p, double rad) {
Point v = (*this) - p;
double c = cos(rad), s = sin(rad);
return Point(p.x + v.x * c - v.y * s, p.y + v.x * s + v.y * c);
}
};
struct cmp {
Point p;
cmp(const Point &p0) {
p = p0;
}
bool operator()(const Point &aa, const Point &bb) {
Point a = aa, b = bb;
int d = sgn((a-p)^(b-p)); // 逆时针,正的就是按角的大小排序
if (!d) return sgn(a.distance(p) - b.distance(p)) < 0; // 由近到远排
return d > 0;
}
};
//极角排序
Point p[N];
void norm(int k) {
Point mi = p[k];
// for (int i = k; i < n; i ++ ) mi = min(mi, p[i]);
sort(p + k, p + n, cmp(mi));
}
map<Point, int> mp;
int res;
int main() {
int T;
cin >> T;
while (T -- ) {
cin >> n;
double yy = 1150;
int idd = -1, id;
for (int i = 0; i < n; i ++ ) {
cin >> id, p[i].input();
mp[p[i]] = id;
if (sgn(p[i].y - yy) < 0) yy = p[i].y, idd = id;
}
cout << n << ' ' << idd << ' ';
swap(p[0], p[idd - 1]);
norm(0);
for (int i = 1; i < n; i ++ ) {
res = i;
norm(i);
cout << mp[p[i]] << " ";
}
cout << endl;
mp.clear();
}
return 0;
}
J
[Link](3347 – Kadj Squares (stdu.edu.cn))
题意
按顺序给你一些正方形的边长,正方形以水平逆时针旋转45°放置。对于每个正方形都要尽量的向左面放且不和前面的覆盖,问你最后从上往下看可以看到哪些正方形。
题解
如果尽量往左边放那么新加入的正方形的一条边一定和前面的某个正方形的边相重合,如果当前正方形的len>相接正方形的len,那么一定是当前正方形的左下边和前面正方形的右上边相切。
发现相接的前面的正方形一定是当前的和前面所有的相切里最远的,而且这个一定是符合的,如果不符合则证明这两个正方形间有正方形,那么新的正方形接到这个覆盖住的一定可以更远,矛盾。我们考虑记录每个正方形最左边L和最右边R可以到哪,所以问题转化成把两个正方形按题目接起来新的正放形的L怎么求,根据几何关系对称性发现,左边 L = ( s q [ i ] . r . − ( x j − x i ) / 2 ) , R = L + 2 × x j L = (sq[i].r. - (xj - xi)/\sqrt2 ),R=L+\sqrt2 \times xj L=(sq[i].r.−(xj−xi)/2),R=L+2×xj。
然后从前到后枚举(根据前面len关系两个正方形的覆盖形式)看这个矩形覆盖了前面的哪个或者被哪个覆盖了,最后枚举一下如果当前矩形的L > R 则证明被完全覆盖了。
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <bitset>
#include <cmath>
#include <stack>
#include <iomanip>
#include <deque>
#include <sstream>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-10, pi = -1.0;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int sgn(double x) {
if (fabs(x) < eps) return 0;
if (x < 0) return -1;
return 1;
}
struct square {
double l, r, len;
}sq[N];
double p = sqrt(double(2));
int main() {
ios::sync_with_stdio(false), cin.tie(0);
while (cin >> n, n) {
for (int i = 0; i < n; i ++ ) {
cin >> sq[i].len;
double l = 0;
for (int j = 0; j < i; j ++ )
l = max(l, sq[j].r - fabs(sq[i].len - sq[j].len) / p);
sq[i].l = l;
sq[i].r = sq[i].l + p * sq[i].len;
}
for (int i = 0; i < n; i ++ )
for (int j = 0; j < i; j ++ )
if (sq[i].l < sq[j].r) {
if (sgn(sq[i].len - sq[j].len) == -1) sq[i].l = sq[j].r;
else sq[j].r = sq[i].l;
}
for (int i = 0; i < n; i ++ )
if (sgn(sq[i].r - sq[i].l) == 1) cout << i + 1 << ' ';
cout << endl;
}
return 0;
}
K
[Link](2826 – An Easy Problem?! (stdu.edu.cn))
题意
给你两个木板,问你这两个木板最多可以接多少水。
题解
给两木板定个序,保证是st是高的点然后分情况讨论即可
-
两线段没交点
跨立交实验判断即可
-
有一个线段和x轴平行
因为定序了,所以只需要看是否当前线段的起点的纵坐标-终点的纵坐标是否等于0即可
-
有一个线段过长了把如水口挡住了
我们分别以两个线段的起点往上方垂直做一条直线,如果有交点就代表被挡住了
-
可以接水
公式求线段交点,然后连接两个起点做croos / 2是对应三角形的面积,然后找到两个st里较高的那个,实际的接水面积占三角形面积的比例就等以较低的到交点/较高的到交点的纵轴的距离的比例。
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <bitset>
#include <cmath>
#include <stack>
#include <iomanip>
#include <deque>
#include <sstream>
#define x first
#define y second
#define debug(x) cout<<"#x"<<:<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = -1;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int sgn(double x) {
if (fabs(x) < eps) return 0;
if (x < 0) return -1;
return 1;
}
struct Point {
double x, y;
Point() {}
Point (double _x, double _y) {
x = _x, y = _y;
}
void input() {
scanf("%lf%lf", &x, &y);
}
void output() {
printf("%.2lf %.2lf", x, y);
}
bool operator ==(Point b) const{
return sgn(x - b.x) == 0 && sgn(y - b.y) == 0;
}
bool operator <(Point b) const{
return sgn(x - b.x) == 0 ? sgn(y - b.y) < 0 : x < b.x;
}
Point operator -(const Point &b) const{
return Point(x - b.x, y - b.y);
}
Point operator +(const Point &b) const{
return Point(x + b.x, y + b.y);
}
Point operator *(const double &t) const{
return Point(x * t, y * t);
}
Point operator /(const double &t) const{
return Point(x / t, y / t);
}
//cross
double operator ^(const Point &b) const{
return x * b.y - y * b.x;
}
// dot
double operator *(const Point &b) const{
return x * b.x + y * b.y;
}
double len() {
return hypot(x, y);
}
double len2() {
return x * x + y * y;
}
double distance(Point p) {
return hypot(x - p.x, y - p.y);
}
// pa pa 夹角
double rad(Point a, Point b) {
Point p = *this;
return fabs(atan2(fabs((a - p) ^ (b - p)), (a - p) * (b - p)));
}
// 转化为长度为r的向量
Point trunc(double r) {
double l = len();
if (!sgn(l)) return *this;
r /= l;
return Point(x * r, y * r);
}
//逆时针旋转90度
Point rotleft() {
return Point(-y, x);
}
//顺时针旋转90度
Point rotright() {
return Point(y, -x);
}
// 绕着p点逆时针旋转 rad度
Point rotate(Point p, double rad) {
Point v = (*this) - p;
double c = cos(rad), s = sin(rad);
return Point(p.x + v.x * c - v.y * s, p.y + v.x * s + v.y * c);
}
};
typedef Point Vector;
struct Line {
Point s, e;
Line() {}
Line(Point _s, Point _e) {
s = _s, e = _e;
}
// 根据一个点和倾斜角 angle 确定直线, 0<=angle< pis
Line(Point p, double angle) {
s = p;
if (sgn(angle - pi / 2) == 0) e = (s + Point(0, 1));
else e = (s + Point(1, tan(angle))); // 往上平移
}
//ax + by + c = 0;
Line(double a, double b, double c) {
if (!sgn(a)) {
s = Point(0, -c / b);
e = Point(1, -c / b);
}
else if (!sgn(b)) {
s = Point(-c / a, 0);
e = Point(-c / a, 1);
}
else {
s = Point(0, -c / b);
e = Point(1, (-c - a) / b);
}
}
bool operator ==(Line v) {
return (s == v.s) && (e == v.e);
}
void input() {
s.input(), e.input();
}
void adjust() {
if (e < s) swap(s, e);
}
// 线段长度
double length() {
return s.distance(e);
}
// 直线倾斜角 0<=angle<pi
double angle() {
double k = atan2(e.y - s.y, e.x - s.x);
if (sgn(k) < 0) k += pi;
if (sgn(k - pi) == 0) k -= pi;
return k;
}
// 点和线的关系 1.左边 2.右边 3.线上
int relation(Point p) {
int c = sgn((p - s) ^ (e - s));
if (c < 0) return 1;
else if (c > 0) return 2;
return 3;
}
//点在线段上
bool pointonseg(Point p) {
return sgn((p-s)^(e-s)) == 0 && sgn((s-p)*(e-p)) <= 0;
}
// 两直线平行
bool parallel(Line v) {
return sgn((e - s) ^ (v.e - v.s)) == 0;
}
// 两线段相交判断 2 规范相交 1 不规范相交 0 不相交
int segcrossseg(Line v) {
int d1 = sgn((e-s)^(v.s-s)), d2 = sgn((e-s)^(v.e-s));
int d3 = sgn((v.e-v.s)^(s-v.s)), d4 = sgn((v.e-v.s)^(e-v.s));
if ((d1^d2) == -2 && (d3^d4) == -2) return 2;
return (d1==0 && sgn((v.s-s)*(v.s-e))<=0) ||
(d2==0 && sgn((v.e-s)*(v.e-e))<=0) ||
(d3==0 && sgn((s-v.s)*(s-v.e))<=0) ||
(d4==0 && sgn((e-v.s)*(e-v.e))<=0);
}
// 直线和线段相交判断 2 规范相交 1 不规范相交 0 不相交 this line v seg
int linecorssseg(Line v) {
int d1 = sgn((e-s)^(v.s-s)), d2 = sgn((e-s)^(v.e-s));
if ((d1^d2) == -2) return 2;
return (!d1 || !d2);
}
// 两直线关系 0 平行 1 重合 2 相交
int linecrossline(Line v) {
if ((*this).parallel(v)) return v.relation(s) == 3;
return 2;
}
// 求两直线的交点,保证不平行和重合
Point crossPoint(Line v) {
double a1 = (v.e-v.s)^(s-v.s), a2 = (v.e-v.s)^(e-v.s);
return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1));
}
double dispointtoline(Point p) {
return fabs((e-s)^(p-s)) / length();
}
double dispointtoseg(Point p) {
if (sgn((e-s)*(p-s)) < 0 || sgn((e-s)*(p-e)) < 0) return min(p.distance(s), p.distance(e));
return dispointtoline(p);
}
// 返回线段和线段的距离,保证不能相交
double dissegtoseg(Line v) {
return min(min(dispointtoseg(v.s), dispointtoseg(v.e)),
min(v.dispointtoseg(s), v.dispointtoseg(e)));
}
// 返回点p在直线上的投影
Point lineprog(Point p) {
return s + (((e-s)*((e-s)*(p-s))/(e-s).len2()));
}
};
// Point segcrosspo(Line a, Line b) {
// Vector u = a.s - b.s;
// double t =
// }
void work(Line l1, Line l2) {
Point p = l1.crossPoint(l2);
Point l = (l1.s.y < l2.s.y ? l1.s : l2.s), r = (l1.s.y > l2.s.y ? l1.s : l2.s);
double res = fabs(((l1.s - p) ^ (l2.s - p))) / 2;
printf("%.2lf\n", res * (l.y - p.y) / (r.y - p.y));
}
bool check(Line a, Line b) {
if (sgn(a.s.y - a.e.y) == 0 || sgn(b.s.y - b.e.y) == 0) return true;
if (!a.segcrossseg(b)) return true;
if (a.segcrossseg(Line(b.s, Point(b.s.x, 10000000))) || b.segcrossseg(Line(a.s, Point(a.s.x, 10000000)))) return true;
return false;
}
int main() {
int T;
cin >> T;
while (T -- ) {
Line l1, l2;
l1.s.input(), l1.e.input(), l2.s.input(), l2.e.input();
if (sgn(l1.s.y - l1.e.y) < 0) swap(l1.s, l1.e);
if (sgn(l2.s.y - l2.e.y) < 0) swap(l2.s, l2.e);
if (check(l1, l2)) printf("%.2lf\n", 0.0);
else work(l1, l2);
}
return 0;
}
L
[Link](1039 – Pipe (stdu.edu.cn))
题意
给你一个管道,然后让你从管口发射一条光(碰到管壁就停止),问该光最远可以到哪。
题解
发现该光一定沿着管道的某个上端和下端射出是最优的,因为不这样一定会更加容易和某个上壁或下壁相交,而且最优解也可以通过旋转,和某个上端和下端点相交。
因此可以暴力枚举上端点和下端点来确定一条直线,然后暴力判断这个直线是否和<u[k],d[k]>有交点,如果没交点则一定没穿过这个管口,和前面的墙壁相撞了,然后找到距离最远的那个即可。
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <bitset>
#include <cmath>
#include <stack>
#include <iomanip>
#include <deque>
#include <sstream>
#define x first
#define y second
#define debug(x) cout<<"#x"<<:<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = -3.14;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int sgn(double x) {
if (fabs(x) < eps) return 0;
if (x < 0) return -1;
return 1;
}
struct Point {
double x, y;
Point() {}
Point (double _x, double _y) {
x = _x, y = _y;
}
void input() {
scanf("%lf%lf", &x, &y);
}
void output() {
printf("%.2lf %.2lf", x, y);
}
bool operator ==(Point b) const{
return sgn(x - b.x) == 0 && sgn(y - b.y) == 0;
}
bool operator <(Point b) const{
return sgn(x - b.x) == 0 ? sgn(y - b.y) < 0 : x < b.x;
}
Point operator -(const Point &b) const{
return Point(x - b.x, y - b.y);
}
Point operator +(const Point &b) const{
return Point(x + b.x, y + b.y);
}
Point operator *(const double &t) const{
return Point(x * t, y * t);
}
Point operator /(const double &t) const{
return Point(x / t, y / t);
}
//cross
double operator ^(const Point &b) const{
return x * b.y - y * b.x;
}
// dot
double operator *(const Point &b) const{
return x * b.x + y * b.y;
}
double len() {
return hypot(x, y);
}
double len2() {
return x * x + y * y;
}
double distance(Point p) {
return hypot(x - p.x, y - p.y);
}
// pa pa 夹角
double rad(Point a, Point b) {
Point p = *this;
return fabs(atan2(fabs((a - p) ^ (b - p)), (a - p) * (b - p)));
}
// 转化为长度为r的向量
Point trunc(double r) {
double l = len();
if (!sgn(l)) return *this;
r /= l;
return Point(x * r, y * r);
}
//逆时针旋转90度
Point rotleft() {
return Point(-y, x);
}
//顺时针旋转90度
Point rotright() {
return Point(y, -x);
}
// 绕着p点逆时针旋转 rad度
Point rotate(Point p, double rad) {
Point v = (*this) - p;
double c = cos(rad), s = sin(rad);
return Point(p.x + v.x * c - v.y * s, p.y + v.x * s + v.y * c);
}
};
typedef Point Vector;
struct Line {
Point s, e;
Line() {}
Line(Point _s, Point _e) {
s = _s, e = _e;
}
// 根据一个点和倾斜角 angle 确定直线, 0<=angle< pis
Line(Point p, double angle) {
s = p;
if (sgn(angle - pi / 2) == 0) e = (s + Point(0, 1));
else e = (s + Point(1, tan(angle))); // 往上平移
}
//ax + by + c = 0;
Line(double a, double b, double c) {
if (!sgn(a)) {
s = Point(0, -c / b);
e = Point(1, -c / b);
}
else if (!sgn(b)) {
s = Point(-c / a, 0);
e = Point(-c / a, 1);
}
else {
s = Point(0, -c / b);
e = Point(1, (-c - a) / b);
}
}
bool operator ==(Line v) {
return (s == v.s) && (e == v.e);
}
void input() {
s.input(), e.input();
}
void adjust() {
if (e < s) swap(s, e);
}
// 线段长度
double length() {
return s.distance(e);
}
// 直线倾斜角 0<=angle<pi
double angle() {
double k = atan2(e.y - s.y, e.x - s.x);
if (sgn(k) < 0) k += pi;
if (sgn(k - pi) == 0) k -= pi;
return k;
}
// 点和线的关系 1.左边 2.右边 3.线上
int relation(Point p) {
int c = sgn((p - s) ^ (e - s));
if (c < 0) return 1;
else if (c > 0) return 2;
return 3;
}
//点在线段上
bool pointonseg(Point p) {
return sgn((p-s)^(e-s)) == 0 && sgn((s-p)*(e-p)) <= 0;
}
// 两直线平行
bool parallel(Line v) {
return sgn((e - s) ^ (v.e - v.s)) == 0;
}
// 两线段相交判断 2 规范相交 1 不规范相交 0 不相交
int segcrossseg(Line v) {
int d1 = sgn((e-s)^(v.s-s)), d2 = sgn((e-s)^(v.e-s));
int d3 = sgn((v.e-v.s)^(s-v.s)), d4 = sgn((v.e-v.s)^(e-v.s));
if ((d1^d2) == -2 && (d3^d4) == -2) return 2;
return (d1==0 && sgn((v.s-s)*(v.s-e))<=0) ||
(d2==0 && sgn((v.e-s)*(v.e-e))<=0) ||
(d3==0 && sgn((s-v.s)*(s-v.e))<=0) ||
(d4==0 && sgn((e-v.s)*(e-v.e))<=0);
}
// 直线和线段相交判断 2 规范相交 1 不规范相交 0 不相交 this line v seg
int linecorssseg(Line v) {
int d1 = sgn((e-s)^(v.s-s)), d2 = sgn((e-s)^(v.e-s));
if ((d1^d2) == -2) return 2;
return (!d1 || !d2);
}
// 两直线关系 0 平行 1 重合 2 相交
int linecrossline(Line v) {
if ((*this).parallel(v)) return v.relation(s) == 3;
return 2;
}
// 求两直线的交点,保证不平行和重合
Point crossPoint(Line v) {
double a1 = (v.e-v.s)^(s-v.s), a2 = (v.e-v.s)^(e-v.s);
return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1));
}
double dispointtoline(Point p) {
return fabs((e-s)^(p-s)) / length();
}
double dispointtoseg(Point p) {
if (sgn((e-s)*(p-s)) < 0 || sgn((e-s)*(p-e)) < 0) return min(p.distance(s), p.distance(e));
return dispointtoline(p);
}
// 返回线段和线段的距离,保证不能相交
double dissegtoseg(Line v) {
return min(min(dispointtoseg(v.s), dispointtoseg(v.e)),
min(v.dispointtoseg(s), v.dispointtoseg(e)));
}
// 返回点p在直线上的投影
Point lineprog(Point p) {
return s + (((e-s)*((e-s)*(p-s))/(e-s).len2()));
}
};
Point u[N], d[N];
void work() {
double res = -1e18;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ ) {
if (i == j) continue;
int k = 1;
for (; k <= n; k ++ ) if (!Line(u[i], d[j]).linecorssseg(Line(u[k], d[k]))) break;
if (k > n) {
printf("Through all the pipe.\n");
return ;
}
if (k < max(i, j)) continue;
double t = 0;
res = max(res, Line(u[i], d[j]).crossPoint(Line(u[k], u[k - 1])).x);
res = max(res, Line(u[i], d[j]).crossPoint(Line(d[k], d[k - 1])).x);
}
printf("%.2lf\n", res);
}
int main() {
while (cin >> n, n) {
for (int i = 1; i <= n; i ++ ) u[i].input(), d[i].x = u[i].x, d[i].y = u[i].y - 1;
work();
}
return 0;
}
M
[Link](3449 – Geometric Shapes (stdu.edu.cn))
题意
给你一些多边形,判断当前多边形和哪些相交。
题解
贼恶心的输入,scanf的优势就出来了,我们可以一点点输入,然后根据输入的字符串判断接下来该输入什么,将A、B这些字母映射成0、1、…。
对于不同的图形我们把他们都存成多边形,方便后面的暴力枚举。
题中的square是只给了两个点x0, x2的,对于另外两个点考虑及方程,首先对顶点到的和/2就是中心坐标因此,x0 + x2 = x1 + x3, y0 + y2 = y1 + y3,先求出01点的向量的等长法向量v,然后中点平移正负v/2即可求出另外两点,x1 = (x0 + x2 + y2 - y0) / 2,x3 = (x0 + x2 + y0 - y2) / 2,y1 = (y0 + y2 + x0 - x2) / 2,y3 = (y0 + y2 - x0 + x2) / 2。求法向量可以将向量逆时针旋转90度,(x, y)逆时针90度数变成(-y,x)。
矩形只给了三个点,可以推出(x3,y3) =(x2+x0-x1, y2+y0-y1);
因为要满足字典序最小因此暴力从0到26枚举它和其它的多边形是否有交点有的话就把他存下来,如果当前这个多边形存在就输出它和他的交多边形。
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <bitset>
#include <cmath>
#include <stack>
#include <iomanip>
#include <deque>
#include <sstream>
#define x first
#define y second
#define debug(x) cout<<"#x"<<:<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 50, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = -3.14;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int a[N];
int sgn(double x) {
if (fabs(x) < eps) return 0;
if (x < 0) return -1;
return 1;
}
struct Point {
double x, y;
Point() {}
Point (double _x, double _y) {
x = _x, y = _y;
}
void input() {
scanf("%lf%lf", &x, &y);
}
void output() {
printf("%.2lf %.2lf", x, y);
}
bool operator ==(Point b) const{
return sgn(x - b.x) == 0 && sgn(y - b.y) == 0;
}
bool operator <(Point b) const{
return sgn(x - b.x) == 0 ? sgn(y - b.y) < 0 : x < b.x;
}
Point operator -(const Point &b) const{
return Point(x - b.x, y - b.y);
}
Point operator +(const Point &b) const{
return Point(x + b.x, y + b.y);
}
Point operator *(const double &t) const{
return Point(x * t, y * t);
}
Point operator /(const double &t) const{
return Point(x / t, y / t);
}
//cross
double operator ^(const Point &b) const{
return x * b.y - y * b.x;
}
// dot
double operator *(const Point &b) const{
return x * b.x + y * b.y;
}
double len() {
return hypot(x, y);
}
double len2() {
return x * x + y * y;
}
double distance(Point p) {
return hypot(x - p.x, y - p.y);
}
// pa pa 夹角
double rad(Point a, Point b) {
Point p = *this;
return fabs(atan2(fabs((a - p) ^ (b - p)), (a - p) * (b - p)));
}
// 转化为长度为r的向量
Point trunc(double r) {
double l = len();
if (!sgn(l)) return *this;
r /= l;
return Point(x * r, y * r);
}
//逆时针旋转90度
Point rotleft() {
return Point(-y, x);
}
//顺时针旋转90度
Point rotright() {
return Point(y, -x);
}
// 绕着p点逆时针旋转 rad度
Point rotate(Point p, double rad) {
Point v = (*this) - p;
double c = cos(rad), s = sin(rad);
return Point(p.x + v.x * c - v.y * s, p.y + v.x * s + v.y * c);
}
};
typedef Point Vector;
struct Line {
Point s, e;
Line() {}
Line(Point _s, Point _e) {
s = _s, e = _e;
}
// 根据一个点和倾斜角 angle 确定直线, 0<=angle< pis
Line(Point p, double angle) {
s = p;
if (sgn(angle - pi / 2) == 0) e = (s + Point(0, 1));
else e = (s + Point(1, tan(angle))); // 往上平移
}
//ax + by + c = 0;
Line(double a, double b, double c) {
if (!sgn(a)) {
s = Point(0, -c / b);
e = Point(1, -c / b);
}
else if (!sgn(b)) {
s = Point(-c / a, 0);
e = Point(-c / a, 1);
}
else {
s = Point(0, -c / b);
e = Point(1, (-c - a) / b);
}
}
bool operator ==(Line v) {
return (s == v.s) && (e == v.e);
}
void input() {
s.input(), e.input();
}
void adjust() {
if (e < s) swap(s, e);
}
// 线段长度
double length() {
return s.distance(e);
}
// 直线倾斜角 0<=angle<pi
double angle() {
double k = atan2(e.y - s.y, e.x - s.x);
if (sgn(k) < 0) k += pi;
if (sgn(k - pi) == 0) k -= pi;
return k;
}
// 点和线的关系 1.左边 2.右边 3.线上
int relation(Point p) {
int c = sgn((p - s) ^ (e - s));
if (c < 0) return 1;
else if (c > 0) return 2;
return 3;
}
//点在线段上
bool pointonseg(Point p) {
return sgn((p-s)^(e-s)) == 0 && sgn((s-p)*(e-p)) <= 0;
}
// 两直线平行
bool parallel(Line v) {
return sgn((e - s) ^ (v.e - v.s)) == 0;
}
// 两线段相交判断 2 规范相交 1 不规范相交 0 不相交
int segcrossseg(Line v) {
int d1 = sgn((e-s)^(v.s-s)), d2 = sgn((e-s)^(v.e-s));
int d3 = sgn((v.e-v.s)^(s-v.s)), d4 = sgn((v.e-v.s)^(e-v.s));
if ((d1^d2) == -2 && (d3^d4) == -2) return 2;
return (d1==0 && sgn((v.s-s)*(v.s-e))<=0) ||
(d2==0 && sgn((v.e-s)*(v.e-e))<=0) ||
(d3==0 && sgn((s-v.s)*(s-v.e))<=0) ||
(d4==0 && sgn((e-v.s)*(e-v.e))<=0);
}
// 直线和线段相交判断 2 规范相交 1 不规范相交 0 不相交 this line v seg
int linecorssseg(Line v) {
int d1 = sgn((e-s)^(v.s-s)), d2 = sgn((e-s)^(v.e-s));
if ((d1^d2) == -2) return 2;
return (!d1 || !d2);
}
// 两直线关系 0 平行 1 重合 2 相交
int linecrossline(Line v) {
if ((*this).parallel(v)) return v.relation(s) == 3;
return 2;
}
// 求两直线的交点,保证不平行和重合
Point crossPoint(Line v) {
double a1 = (v.e-v.s)^(s-v.s), a2 = (v.e-v.s)^(e-v.s);
return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1));
}
double dispointtoline(Point p) {
return fabs((e-s)^(p-s)) / length();
}
double dispointtoseg(Point p) {
if (sgn((e-s)*(p-s)) < 0 || sgn((e-s)*(p-e)) < 0) return min(p.distance(s), p.distance(e));
return dispointtoline(p);
}
// 返回线段和线段的距离,保证不能相交
double dissegtoseg(Line v) {
return min(min(dispointtoseg(v.s), dispointtoseg(v.e)),
min(v.dispointtoseg(s), v.dispointtoseg(e)));
}
// 返回点p在直线上的投影
Point lineprog(Point p) {
return s + (((e-s)*((e-s)*(p-s))/(e-s).len2()));
}
};
struct polygon {
int n;
Point p[N];
Line l[N];
void input(int _n) {
n = _n;
for (int i = 0; i < n; i ++ ) p[i].input();
}
void add(Point q) {
p[n ++] = q;
}
void getline() {
for (int i = 0; i < n; i ++ )
l[i] = Line(p[i], p[(i + 1) % n]);
}
struct cmp {
Point p;
cmp(const Point &p0) {
p = p0;
}
bool operator() (const Point &aa, const Point &bb) {
Point a = aa, b = bb;
int d = sgn((a - p) ^ (b - p));
if (!d) return sgn(a.distance(p) - b.distance(p)) < 0;
return d > 0;
}
};
void norm() { // 极角排序
Point mi = p[0];
for (int i = 1; i < n; i ++ ) mi = min(mi, p[i]);
sort(p, p + n, cmp(mi));
}
void getconvex(polygon &convex) { // 上凸包,下凸包、顺时针,rotate
sort(p, p + n);
convex.n = n;
for (int i = 0; i < min(n, 2); i ++ ) {
convex.p[i] = p[i];
}
if (convex.n == 2 && (convex.p[0] == convex.p[1])) convex.n --;
if (n <= 2) return ;
int &top = convex.n;
top = 1;
for (int i = 2; i < n; i ++ ) {
while (top && sgn((convex.p[top] - p[i]) ^ (convex.p[top - 1] - p[i])) <= 0) top --;
convex.p[++top] = p[i];
}
int temp = top;
convex.p[++top] = p[n-2];
for (int i = n - 3; i >= 0; i -- ) {
while (top != temp && sgn((convex.p[top] - p[i]) ^ (convex.p[top - 1] - p[i])) <= 0) top --;
convex.p[++top] = p[i];
}
if (convex.n == 2 && (convex.p[0] == convex.p[1])) convex.n --;
convex.norm();
}
bool check(polygon b) {
if (n && b.n) {
for (int i = 0; i < n; i ++ )
for (int j = 0; j < b.n; j ++ )
if (Line(p[i], p[(i + 1) % n]).segcrossseg(Line(b.p[j], b.p[(j + 1) % b.n])))
return true;
}
return false;
}
};
polygon poly[N];
int main() {
char str[10], strr[20];
memset(poly, 0, sizeof poly);
while (scanf("%s", str) != EOF) {
if (!strcmp(str, ".")) break;
if (!strcmp(str, "-")) {
char c[30];
for (int i = 0; i < 26; i ++ ) {
int k = 0;
for (int j = 0; j < 26; j ++ ) {
if (i != j && poly[i].check(poly[j])) c[k ++] = 'A' + j;
}
if (!k && poly[i].n) printf("%c has no intersections\n",i+'A');
else if (poly[i].n) {
printf("%c intersects with %c",i+'A',c[0]);
if(k == 2)
{
printf(" and %c",c[1]);
}
else if(k > 2)
{
for(int m = 1; m < k-1; m++)
{
printf(", %c",c[m]);
}
printf(", and %c",c[k-1]);
}
printf("\n");
}
}
printf("\n");
memset(poly, 0, sizeof poly);
continue;
}
scanf("%s", strr);
int tmp = str[0] - 'A';
double x, y;
if (!strcmp(strr, "square")) {
poly[tmp].n = 4;
scanf(" (%lf,%lf)", &x, &y);
// Point &p[4] = poly[tmp].p;
poly[tmp].p[0].x = x, poly[tmp].p[0].y = y;
scanf(" (%lf,%lf)", &x, &y);
poly[tmp].p[2].x = x, poly[tmp].p[2].y = y;
poly[tmp].p[1].x = (poly[tmp].p[0].x + poly[tmp].p[2].x + poly[tmp].p[2].y - poly[tmp].p[0].y) / 2;
poly[tmp].p[1].y = (poly[tmp].p[0].y + poly[tmp].p[2].y + poly[tmp].p[0].x - poly[tmp].p[2].x) / 2;
poly[tmp].p[3].x = (poly[tmp].p[0].x + poly[tmp].p[2].x + poly[tmp].p[0].y - poly[tmp].p[2].y) / 2;
poly[tmp].p[3].y = (poly[tmp].p[0].y + poly[tmp].p[2].y + poly[tmp].p[2].x - poly[tmp].p[0].x) / 2;
}
else if (!strcmp(strr, "rectangle")) {
poly[tmp].n = 4;
scanf(" (%lf,%lf)", &x, &y);
poly[tmp].p[0].x = x, poly[tmp].p[0].y = y;
scanf(" (%lf,%lf)", &x, &y);
poly[tmp].p[1].x = x, poly[tmp].p[1].y = y;
scanf(" (%lf,%lf)", &x, &y);
poly[tmp].p[2].x = x, poly[tmp].p[2].y = y;
poly[tmp].p[3].x = (poly[tmp].p[0].x + poly[tmp].p[2].x - poly[tmp].p[1].x);
poly[tmp].p[3].y = (poly[tmp].p[2].y - poly[tmp].p[1].y + poly[tmp].p[0].y);
}
else if (!strcmp(strr, "line")) {
poly[tmp].n = 2;
scanf(" (%lf,%lf)", &x, &y);
poly[tmp].p[0].x = x, poly[tmp].p[0].y = y;
scanf(" (%lf,%lf)", &x, &y);
poly[tmp].p[1].x = x, poly[tmp].p[1].y = y;
}
else if (!strcmp(strr, "polygon")) {
scanf("%d", &n);
poly[tmp].n = n;
for (int i = 0; i < n; i ++ ) {
scanf(" (%lf,%lf)", &x, &y);
poly[tmp].p[i].x = x, poly[tmp].p[i].y = y;
}
}
else {
poly[tmp].n = 3;
scanf(" (%lf,%lf)", &x, &y);
poly[tmp].p[0].x = x, poly[tmp].p[0].y = y;
scanf(" (%lf,%lf)", &x, &y);
poly[tmp].p[1].x = x, poly[tmp].p[1].y = y;
scanf(" (%lf,%lf)", &x, &y);
poly[tmp].p[2].x = x, poly[tmp].p[2].y = y;
}
}
return 0;
}
N
[link](1584 – A Round Peg in a Ground Hole (poj.org))
题意
给你一个圆和一些点,让你判断这个这些点是否可以构成一个凸包,以及这个圆和多边形的关系。
题解
首先判断凸包可以看相邻两个边的cross是否都是同号的即可。
判断点是否在多边形内的方法
-
射线法
做一条平行x轴的射线穿过的线段的个数为奇数
-
转角法
枚举相邻的边和这个点求转过的角度,360在内部,180在边上,其余在外边
-
面积法
点和每个边的两个端点连线做cross一定是同号的
判断圆是否在多边形的内部
只需判断圆心到每条线的距离是否大于半径即可
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <bitset>
#include <cmath>
#include <stack>
#include <iomanip>
#include <deque>
#include <sstream>
#define x first
#define y second
#define debug(x) cout<<"#x"<<:<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = -1;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int sgn(double x) {
if (fabs(x) < eps) return 0;
if (x < 0) return -1;
return 1;
}
struct Point {
double x, y;
Point() {}
Point (double _x, double _y) {
x = _x, y = _y;
}
void input() {
scanf("%lf%lf", &x, &y);
}
void output() {
printf("%.2lf %.2lf", x, y);
}
bool operator ==(Point b) const{
return sgn(x - b.x) == 0 && sgn(y - b.y) == 0;
}
bool operator <(Point b) const{
return sgn(x - b.x) == 0 ? sgn(y - b.y) < 0 : x < b.x;
}
Point operator -(const Point &b) const{
return Point(x - b.x, y - b.y);
}
Point operator +(const Point &b) const{
return Point(x + b.x, y + b.y);
}
Point operator *(const double &t) const{
return Point(x * t, y * t);
}
Point operator /(const double &t) const{
return Point(x / t, y / t);
}
//cross
double operator ^(const Point &b) const{
return x * b.y - y * b.x;
}
// dot
double operator *(const Point &b) const{
return x * b.x + y * b.y;
}
double len() {
return hypot(x, y);
}
double len2() {
return x * x + y * y;
}
double distance(Point p) {
//return hypot(x - p.x, y - p.y);
return sqrt(((x - p.x) * (x - p.x) + (y - p.y) * (y - p.y)));
}
// pa pa 夹角
double rad(Point a, Point b) {
Point p = *this;
return fabs(atan2(fabs((a - p) ^ (b - p)), (a - p) * (b - p)));
}
// 转化为长度为r的向量
Point trunc(double r) {
double l = len();
if (!sgn(l)) return *this;
r /= l;
return Point(x * r, y * r);
}
//逆时针旋转90度
Point rotleft() {
return Point(-y, x);
}
//顺时针旋转90度
Point rotright() {
return Point(y, -x);
}
// 绕着p点逆时针旋转 rad度
Point rotate(Point p, double rad) {
Point v = (*this) - p;
double c = cos(rad), s = sin(rad);
return Point(p.x + v.x * c - v.y * s, p.y + v.x * s + v.y * c);
}
};
typedef Point Vector;
struct Line {
Point s, e;
Line() {}
Line(Point _s, Point _e) {
s = _s, e = _e;
}
// 根据一个点和倾斜角 angle 确定直线, 0<=angle< pis
Line(Point p, double angle) {
s = p;
if (sgn(angle - pi / 2) == 0) e = (s + Point(0, 1));
else e = (s + Point(1, tan(angle))); // 往上平移
}
//ax + by + c = 0;
Line(double a, double b, double c) {
if (!sgn(a)) {
s = Point(0, -c / b);
e = Point(1, -c / b);
}
else if (!sgn(b)) {
s = Point(-c / a, 0);
e = Point(-c / a, 1);
}
else {
s = Point(0, -c / b);
e = Point(1, (-c - a) / b);
}
}
bool operator ==(Line v) {
return (s == v.s) && (e == v.e);
}
void input() {
s.input(), e.input();
}
void adjust() {
if (e < s) swap(s, e);
}
// 线段长度
double length() {
return s.distance(e);
}
// 直线倾斜角 0<=angle<pi
double angle() {
double k = atan2(e.y - s.y, e.x - s.x);
if (sgn(k) < 0) k += pi;
if (sgn(k - pi) == 0) k -= pi;
return k;
}
// 点和线的关系 1.左边 2.右边 3.线上
int relation(Point p) {
int c = sgn((p - s) ^ (e - s));
if (c < 0) return 1;
else if (c > 0) return 2;
return 3;
}
//点在线段上
bool pointonseg(Point p) {
return sgn((p-s)^(e-s)) == 0 && sgn((s-p)*(e-p)) <= 0;
}
// 两直线平行
bool parallel(Line v) {
return sgn((e - s) ^ (v.e - v.s)) == 0;
}
// 两线段相交判断 2 规范相交 1 不规范相交 0 不相交
int segcrossseg(Line v) {
int d1 = sgn((e-s)^(v.s-s)), d2 = sgn((e-s)^(v.e-s));
int d3 = sgn((v.e-v.s)^(s-v.s)), d4 = sgn((v.e-v.s)^(e-v.s));
if ((d1^d2) == -2 && (d3^d4) == -2) return 2;
return (d1==0 && sgn((v.s-s)*(v.s-e))<=0) ||
(d2==0 && sgn((v.e-s)*(v.e-e))<=0) ||
(d3==0 && sgn((s-v.s)*(s-v.e))<=0) ||
(d4==0 && sgn((e-v.s)*(e-v.e))<=0);
}
// 直线和线段相交判断 2 规范相交 1 不规范相交 0 不相交 this line v seg
int linecorssseg(Line v) {
int d1 = sgn((e-s)^(v.s-s)), d2 = sgn((e-s)^(v.e-s));
if ((d1^d2) == -2) return 2;
return (!d1 || !d2);
}
// 两直线关系 0 平行 1 重合 2 相交
int linecrossline(Line v) {
if ((*this).parallel(v)) return v.relation(s) == 3;
return 2;
}
// 求两直线的交点,保证不平行和重合
Point crossPoint(Line v) {
double a1 = (v.e-v.s)^(s-v.s), a2 = (v.e-v.s)^(e-v.s);
return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1));
}
double dispointtoline(Point p) {
return fabs((e-s)^(p-s)) / length();
}
double dispointtoseg(Point p) {
if (sgn((e-s)*(p-s)) < 0 || sgn((e-s)*(p-e)) < 0) return min(p.distance(s), p.distance(e));
return dispointtoline(p);
}
// 返回线段和线段的距离,保证不能相交
double dissegtoseg(Line v) {
return min(min(dispointtoseg(v.s), dispointtoseg(v.e)),
min(v.dispointtoseg(s), v.dispointtoseg(e)));
}
// 返回点p在直线上的投影
Point lineprog(Point p) {
return s + (((e-s)*((e-s)*(p-s))/(e-s).len2()));
}
};
struct polygon {
int n;
Point p[N];
Line l[N];
void input(int _n) {
n = _n;
for (int i = 0; i < n; i ++ ) p[i].input();
}
void add(Point q) {
p[n ++] = q;
}
void getline() {
for (int i = 0; i < n; i ++ )
l[i] = Line(p[i], p[(i + 1) % n]);
}
struct cmp {
Point p;
cmp(const Point &p0) {
p = p0;
}
bool operator() (const Point &aa, const Point &bb) {
Point a = aa, b = bb;
int d = sgn((a - p) ^ (b - p));
if (!d) return sgn(a.distance(p) - b.distance(p)) < 0;
return d > 0;
}
};
void norm() { // 极角排序
Point mi = p[0];
for (int i = 1; i < n; i ++ ) mi = min(mi, p[i]);
sort(p, p + n, cmp(mi));
}
void getconvex(polygon &convex) { // 上凸包,下凸包、顺时针,rotate
sort(p, p + n);
convex.n = n;
for (int i = 0; i < min(n, 2); i ++ ) {
convex.p[i] = p[i];
}
if (convex.n == 2 && (convex.p[0] == convex.p[1])) convex.n --;
if (n <= 2) return ;
int &top = convex.n;
top = 1;
for (int i = 2; i < n; i ++ ) {
while (top && sgn((convex.p[top] - p[i]) ^ (convex.p[top - 1] - p[i])) <= 0) top --;
convex.p[++top] = p[i];
}
int temp = top;
convex.p[++top] = p[n-2];
for (int i = n - 3; i >= 0; i -- ) {
while (top != temp && sgn((convex.p[top] - p[i]) ^ (convex.p[top - 1] - p[i])) <= 0) top --;
convex.p[++top] = p[i];
}
if (convex.n == 2 && (convex.p[0] == convex.p[1])) convex.n --;
convex.norm();
}
};
struct Circle {
Point p;
double r;
Circle(){}
};
Circle c;
Point p[N];
bool is_convex() {
double fir = 0;
for (int i = 0; i < n; i ++ ) {
double res = sgn((p[(i + 1) % n] - p[i]) ^ (p[(i + 2) % n] - p[(i + 1) % n]));
if (!fir) fir = res;
if (res * fir < 0) return false;
}
return true;
}
bool check_pin() {
double res = 0;
for (int i = 0; i < n; i ++ ) {
double t = sgn((p[i] - c.p) ^ (p[(i + 1) % n] - c.p));
if (!res) res = t;
if (res * t < 0) return false;
}
return true;
}
bool check_cin() {
for (int i = 0; i < n; i ++ ) {
double d = fabs(((p[i] - c.p) ^ (p[(i + 1) % n] - c.p))) / Line(p[i], p[i + 1]).length();
if (sgn(d - c.r) < 0) return false;
}
return true;
}
int main() {
// ios::sync_with_stdio(false), cin.tie(0);
while (cin >> n) {
if (n < 3) break;
cin >> c.r >> c.p.x >> c.p.y;
for (int i = 0; i < n; i ++ ) p[i].input();
if (!is_convex()) puts("HOLE IS ILL-FORMED");
else {
bool ok1 = check_pin(),ok2;
if (ok1) ok2 = check_cin();
if (ok1 && ok2) puts("PEG WILL FIT");
else puts("PEG WILL NOT FIT");
}
}
return 0;
}