博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
计算几何题集
阅读量:3951 次
发布时间:2019-05-24

本文共 14355 字,大约阅读时间需要 47 分钟。

文章目录

判断点和射线的那边

向量叉乘判断符号解决。向量叉乘使用右手法则。

v 1 = ( x 1 , y 1 ) , v 2 = ( x 2 , y 2 ) v 1 × v 2 = x 1 ∗ y 2 − y 1 ∗ x 2 v_1=(x1,y1),v2=(x2,y2) \\ v1×v2=x1*y2-y1*x2 v1=(x1,y1),v2=(x2,y2)v1×v2=x1y2y1x2
在这里插入图片描述
例:
依次给出三个点,求是顺时针旋转还是逆时针。
s = v 13 × v 23 = ( x 1 − x 3 ) ( y 2 − y 3 ) − ( y 1 − y 3 ) ( x 2 − x 3 ) s=v_{13}×v_{23}= (x1-x3)(y2-y3)-(y1-y3)(x2-x3) s=v13×v23=(x1x3)(y2y3)(y1y3)(x2x3)
则结合右手法则可知,
{ s < 0 , 顺 时 针 s > 0 , 逆 时 针 \{\begin{aligned}s<0, 顺时针\\ s>0, 逆时针\end{aligned} {
s<0,s>0,

判断n个线段能否投影到一条直线上至少有一个共同点。容易转化为问题:n个线段是否能被一条直线(与投影轴垂直)穿过。枚举所有点两两成的直线能否串过所有线段。用跨立实验判断直线和线段是否相交。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;// #define endl '\n'typedef long long ll;typedef pair
pii;const int maxn=1e5+3;const ll mod = 1e9+7;struct Point{ double x,y; Point operator- (const Point &v) const { return Point{ x-v.x, y-v.y}; } int operator* (const Point &v) const { double flag = x*v.y - y*v.x; if(abs(flag)<1e-8)return 0; return flag>0 ? 1 : -1; } double len(){ return sqrt(x*x+y*y); }};struct Line{ Point p1, p2; int judge_point(Point v){ Point pa = p1 - p2; Point pb = p1 - v; return pa * pb; }};Point p[305];Line seg[305];int main(){ ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); int tt; cin>>tt; while(tt--){ int n; cin>>n; for(int i=0;i<2*n;++i){ cin>>p[i].x>>p[i].y; } for(int i=0;i

求两直线交点

x0 = ((x3-x4) * (x2*y1 - x1*y2) - (x1-x2) * (x4*y3 - x3*y4)) / ((x3-x4) * (y1-y2) - (x1-x2) * (y3-y4));y0 = ((y3-y4) * (y2*x1 - y1*x2) - (y1-y2) * (y4*x3 - y3*x4)) / ((y3-y4) * (x1-x2) - (y1-y2) * (x3-x4));
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;// #define endl '\n'typedef long long ll;typedef pair
pii;const int maxn=1e5+3;const ll mod = 1e9+7;struct Point{ double x,y; Point operator- (const Point &v) const { return Point{ x-v.x, y-v.y}; } int operator* (const Point &v) const { double flag = x*v.y - y*v.x; if(abs(flag)<1e-8)return 0; return flag>0 ? 1 : -1; } double len(){ return sqrt(x*x+y*y); }};struct Line{ Point p1, p2; int judge_point(Point v){ Point pa = p1 - p2; Point pb = p1 - v; return pa * pb; }};Point p[305];Line seg[305];int main(){ ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); int tt; cin>>tt; cout<<"INTERSECTING LINES OUTPUT"<
>la.p1.x>>la.p1.y>>la.p2.x>>la.p2.y>>lb.p1.x>>lb.p1.y>>lb.p2.x>>lb.p2.y; Point va = la.p1 - la.p2; Point vb = lb.p1 - lb.p2; int flag = va * vb; if(!flag){ if(!la.judge_point(lb.p1))cout<<"LINE"<

在这里插入图片描述
每个点两两看有没有穿过墙,没穿过则建边,跑最短路。
没有做快速排斥实验,因为不可能有边与墙共线的情况。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// #define endl '\n'using namespace std;#define debug(_x) cout<<#_x<<": "<<_x<
0 && ((l2.p1 - l1.p1) ^ d2) * (d2 ^ (l2.p1 - l1.p2)) > 0;}struct Edge{ int to; double dis; bool operator< (const Edge& v){ return dis>v.dis; }};int main(){ ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); int n; while(cin>>n && ~n){ vector
p; vector
e; p.push_back(Point{ 0,5}); for(int k=0;k
>tx; for(int i=0;i<4;++i){ cin>>y[i]; p.push_back(Point{ tx,y[i]}); } e.push_back(Line{ Point{ tx,0},Point{ tx,y[0]}}); e.push_back(Line{ Point{ tx,y[1]},Point{ tx,y[2]}}); e.push_back(Line{ Point{ tx,y[3]},Point{ tx,10}}); } p.push_back(Point{ 10,5}); vector
> G(p.size()); vector
in(p.size()); vector
d(p.size(), 1e8); for(int i=0;i
Q; d[0] = 0; Q.push(Edge{ 0,0}); while(!Q.empty()){ Edge u = Q.front(); in[u.to] = 0; Q.pop(); for(int i=0;i
d[u.to]+v.dis){ d[v.to] = d[u.to] + v.dis; if(in[v.to])continue; in[v.to] = 1; v.dis = d[v.to]; Q.push(v); } } } cout<
<
<
<

木棒压木棒,求没被压的木棒。
在这里插入图片描述

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;// #define endl '\n'typedef long long ll;typedef pair
pii;struct Point{ double x, y; double operator* (const Point &p) const { return x*p.y - p.x*y; } Point operator- (const Point &p) const { return Point{ x-p.x, y-p.y}; } double len(){ return sqrt(x*x+y*y); }};struct Line{ Point a,b; Point dir() const{ return a - b; } double judge_point(const Point &p) const{ return this->dir() * (a - p); }};bool iscross(Line s1,Line s2){ return min(s1.a.x,s1.b.x) < max(s2.a.x,s2.b.x) && min(s1.a.y,s1.b.y) < max(s2.a.y,s2.b.y) && min(s2.a.x,s2.b.x) < max(s1.a.x,s1.b.x) && min(s2.a.y,s2.b.y) < max(s1.a.y,s1.b.y) && s1.judge_point(s2.a) * s1.judge_point(s2.b) <= 0 && s2.judge_point(s1.a) * s2.judge_point(s1.b) <= 0;}int main(){ int n; while(~scanf("%d", &n) && n){ list
> lines; Line tl; for(int i = 0;i < n;++i){ scanf("%lf%lf%lf%lf",&tl.a.x,&tl.a.y,&tl.b.x,&tl.b.y); for(list
>::iterator it = lines.begin();it!=lines.end();){ if(iscross(it->first, tl))it = lines.erase(it); else ++it; } lines.push_back(make_pair(tl, i+1)); } printf("Top sticks: %d", lines.begin()->second); for(list
>::iterator it = lines.begin();it!=lines.end();++it){ if(it == lines.begin())continue; printf(", %d", it->second); } printf(".\n"); }}

在这里插入图片描述
每次从线段的中点穿过,问穿过多少面墙能到达宝藏位置。由于每条直线穿过整个正方形。转弯无法减少穿过数。所以枚举每个中点作射线就行。而枚举每个顶点也一样。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;// #define endl '\n'typedef long long ll;typedef pair
pii;struct Point{ double x, y; double operator* (const Point &p) const { return x*p.y - p.x*y; } Point operator- (const Point &p) const { return Point{ x-p.x, y-p.y}; } double len(){ return sqrt(x*x+y*y); } bool operator== (const Point &p) const { return x==p.x && y==p.y; }};struct Line{ Point a,b; Point dir() const{ return a - b; } double judge_point(const Point &p) const{ return this->dir() * (a - p); }};bool iscross(Line s1,Line s2){ return min(s1.a.x,s1.b.x) <= max(s2.a.x,s2.b.x) && min(s1.a.y,s1.b.y) <= max(s2.a.y,s2.b.y) && min(s2.a.x,s2.b.x) <= max(s1.a.x,s1.b.x) && min(s2.a.y,s2.b.y) <= max(s1.a.y,s1.b.y) && s1.judge_point(s2.a) * s1.judge_point(s2.b) < 1e-8 && s2.judge_point(s1.a) * s2.judge_point(s1.b) < 1e-8;}int main(){ int n; while(~scanf("%d", &n)){ vector
lines; vector
p; Line tl; for(int i = 0;i < n;++i){ scanf("%lf%lf%lf%lf",&tl.a.x,&tl.a.y,&tl.b.x,&tl.b.y); lines.push_back(tl); p.push_back(tl.a); p.push_back(tl.b); } int ans = 1e9; scanf("%lf%lf",&tl.b.x,&tl.b.y); for(int k=0;k
2*n)ans = 1; printf("Number of doors = %d\n", ans); }}

在这里插入图片描述
从Plant A出发,只能往左转最多能走多少个点,依次输出。只要每次选当前点为基准,极角排序,选极角最小的,必能走完所有的点。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define endl '\n'using namespace std;struct Point{ int idx; int x, y; int operator^ (const Point &p) const{ return x*p.y - y*p.x; } Point operator- (const Point &p) const{ return Point{ 0, x-p.x, y-p.y}; } double len(){ return sqrt(x*x+y*y); }};int sgn(const int x){ if(abs(x)<1e-8)return 0; return x < 0 ? -1 : 1;}Point mark;bool cmp(const Point &a, const Point &b){ Point da = a - mark; Point db = b - mark; switch(sgn(da ^ db)){ case 1: return 1; case -1: return 0; default: return da.len() < db.len(); }}int main(){ ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); int tt; cin>>tt; while(tt--){ int n; cin>>n; vector
v(n); for(int i=0;i
>v[i].idx>>v[i].x>>v[i].y; if(!i)mark = v[i]; else if(v[i].y < mark.y)mark = v[i]; } swap(v[mark.idx-1],v[0]); for(int i=1;i

给出N个乱序的点,问这些点能不能组成正N边形。
思路:先找到y坐标最小的那个点,作为第一个点,将后面N-1个点依次以上一个点为KEY点做极角排序。判断每条边长度是否相同,相邻边的角度是否相同(可用内积,外积)。

#include 
#define endl '\n'using namespace std;const int inf = 2e9;const double eps = 1e-6;using ll = long long;struct Point{
int x, y; double len(){
return sqrt(1ll*x*x+1ll*y*y); } Point operator- (const Point& ot) const{
return Point{
x-ot.x, y-ot.y}; } ll operator* (const Point& ot) const{
return x*ot.y - y*ot.x; }}key;int sgn(double x){
if(x==0)return 0; return x < 0 ? -1 : 1;}bool cmp(const Point& a, const Point& b){
Point va = a - key, vb = b - key; switch(sgn(va * vb)){
case 0: return va.len() < vb.len(); case 1: return 1; case -1: return 0; }}int main(){
int tt; ios::sync_with_stdio(false); cin.tie(0), cout.tie(0); cin >> tt; while(tt--){
int n; cin >> n; vector
v; int idx = 0; for(int i=0;i
> x.x >> x.y; v.push_back(x); if(x.y < v[0].y || x.y==v[0].y && x.x < v[0].x) swap(v[i], v[0]); } for(int i=0;i+1

求二维凸包的周长。

#include 
#define endl '\n'using namespace std;const int inf = 2e9;const double eps = 1e-6;using ll = long long;using pdd = pair
;const double PI = acos(-1);const int maxn = 2e5+5;int sgn(double x){
if(x==0)return 0; return x < 0 ? -1 : 1;}struct Point{
int x, y; double len(){
return sqrt(1ll*x*x+1ll*y*y); } Point operator- (const Point& ot) const{
return Point{
x-ot.x, y-ot.y}; } ll operator* (const Point& ot) const{
return x*ot.y - y*ot.x; }}key, sta[maxn];bool cmp(const Point& a, const Point& b){
Point va = a - key, vb = b - key; switch(sgn(va * vb)){
case 0: return va.len() < vb.len(); case 1: return 1; case -1: return 0; }}int main(){
int tt; ios::sync_with_stdio(false); cin.tie(0), cout.tie(0); int n; while(cin >> n && n){
vector
v(n); for(Point& p : v){
cin >> p.x >> p.y; } if(n==1){
cout << 0 << endl; continue; }else if(n==2){
cout << fixed << setprecision(2) << (v[1] - v[0]).len() << endl; continue; } int id = 0; for(int i=1;i
0 && sgn( (sta[top] - sta[top-1]) * (v[i] - sta[top]) ) < 0) top--; // 踢掉右转的 sta[++top] = v[i]; } double sum = 0; sta[++top] = v[0]; for(int i=0;i

旋转卡壳

题意:二维平面给一堆点,求最小的矩形包括所有的点。输出矩形面积和4个坐标。
思路:旋转卡壳模板。维护三个卡壳点,因为三者都是单峰函数,所以可以实现。

  • p是离当前枚举边 ( i , i + 1 ) (i, i + 1) (i,i+1)最远的点,用叉乘求三角形面积来判断,通过p就求出了矩形的高H
  • fr是所有点投影到当前枚举边 ( i , i + 1 ) (i, i + 1) (i,i+1),设 i i i i + 1 i+1 i+1为正方向,最负的点
  • ba是最正的点,fr、ba使用点乘求投影来判断
#include
// #define endl '\n'#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);using namespace std;const int N = 5e4 +5;const double eps = 1e-10;struct Coor{
double x, y; double operator^ (const Coor & ot) const &{
return x * ot.y - y * ot.x; } double operator* (const Coor & ot) const &{
return x * ot.x + y * ot.y; } double len(){
return sqrt(x * x + y * y); } Coor operator- (const Coor & ot) const &{
return Coor{
x - ot.x, y - ot.y}; } Coor operator+ (const Coor & ot) const &{
return Coor{
x + ot.x, y + ot.y}; }}a[N], sta[N], key, rect[4];Coor operator* (const double & c, const Coor & v){
return Coor{
v.x * c, v.y * c};}int sgn(double v){
if(abs(v) < eps)return 0; return v < 0 ? -1 : 1;}bool cmp(const Coor &a, const Coor &b){
Coor da = a - key, db = b - key; switch(sgn(da ^ db)){
case 1: return true; case -1: return false; default: return da.len() < db.len(); }}double area(int i, int j, int k){
return (sta[j] - sta[i]) ^ (sta[k] - sta[i]);}double project(int i, int j, int k){
return (sta[j] - sta[i]) * (sta[k] - sta[i]);}int main(){
IOS; int n; cin >> n; int id = 0; for(int i = 0; i < n; ++i){
cin >> a[i].x >> a[i].y; if(a[i].y < a[id].y || a[i].y == a[id].y && a[i].x < a[id].x)id = i; } swap(a[id], a[0]); key = a[0]; sort(a+1, a+n, cmp); int top = 0; sta[0] = a[0];#define U(_ar, _i) cout << "(" << _ar[_i].x << "," << _ar[_i].y << ") "; for(int i = 1; i < n; ++i){
while(top > 0 && sgn((sta[top] - sta[top - 1]) ^ (a[i] - sta[top])) <= 0)top--; sta[++top] = a[i]; } sta[++top] = sta[0]; int p = 1, ba = 1, fr = 1; double ans = 2e14; for(int i = 0; i < top; ++i){
while(sgn(area(i, i + 1, p) - area(i, i + 1, p + 1)) <= 0) p = (p + 1) % top; while(sgn(project(i, i + 1, fr)) > 0 || sgn(project(i, i + 1, fr) - project(i, i + 1, (fr + 1) % top)) >= 0) fr = (fr + 1) % top; while(sgn(project(i, i + 1, ba) - project(i, i + 1, (ba + 1) % top)) < 0) ba = (ba + 1) % top; double L = (sta[i + 1] - sta[i]).len(), H = area(i, i + 1, p), C = (sta[i + 1] - sta[i]) * (sta[ba] - sta[fr]);// assert(sgn(C) > 0);// assert(sgn(H) > 0); if(sgn(H * C - ans * L * L) < 0){
ans = H * C / (L * L); H /= L; Coor I = 1 / L * (sta[i + 1] - sta[i]); // 单位向量 double pf = (sta[fr] - sta[i]) * I; // f投影大小 double pb = (sta[ba] - sta[i]) * I; // b投影大小 rect[0] = sta[i] + pf * I; rect[1] = sta[i] + pb * I; Coor Vert = sgn(I.y) == 0 ? Coor{
0, 1} : Coor{
1, -I.x / I.y}; if(sgn(I ^ Vert) < 0)Vert = -1 * Vert; Vert = H / Vert.len() * Vert; rect[2] = rect[1] + Vert; rect[3] = rect[0] + Vert;// cout << ans << endl;// for(int fi = 0, i = 0; i < 4; ++i){
// cout << rect[fi].x << " " << rect[fi].y << endl;// fi = (fi + 1) % 4;// } } } if(sgn(ans) == 0) ans = 0; cout << fixed << setprecision(5) << ans + 1e-8 << endl; int fi = 0; for(int i = 1; i < 4; ++i){
if(sgn(rect[i].y - rect[fi].y) < 0 || sgn(rect[i].y - rect[fi].y) == 0 && sgn(rect[i].x - rect[fi].x) < 0) fi = i; } for(int i = 0; i < 4; ++i){
if(sgn(rect[fi].x) == 0)rect[fi].x = 0; if(sgn(rect[fi].y) == 0)rect[fi].y = 0; cout << rect[fi].x << " " << rect[fi].y << endl; fi = (fi + 1) % 4; }}

转载地址:http://lgkzi.baihongyu.com/

你可能感兴趣的文章
进程看门狗
查看>>
线程看门狗
查看>>
调试代码的宏定义
查看>>
创建、重命名文件
查看>>
文件大小保护
查看>>
删除指定目录下所有文件及目录
查看>>
XDR-从文件空间解码整数
查看>>
XDR-.x文件的简单使用
查看>>
XDR-枚举的试用
查看>>
使用CppSQLite3访问SQLite数据库
查看>>
第一个boost程序---timer的使用
查看>>
使用boost asio库实现字节数可控的CS通信
查看>>
linux下串口编程
查看>>
boot asio 非阻塞同步编程---非阻塞的accept和receive。
查看>>
利用ADOX、ADO操纵MDB文件(ACCESS)
查看>>
使用ADO操作MDB,关注数据类型
查看>>
使用windows自带Zip命令压缩文件
查看>>
windows获得文件大小
查看>>
Host 'ETCV3' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'
查看>>
OCILIB在VS2008中的使用
查看>>