计算几何第一题:POJ-2318-TOYS
题意
用
n
条
总
左
到
右
排
好
序
的
直
线
分
成
将
一
个
长
方
形
分
成
n
+
1
个
区
域
用n条总左到右排好序的直线分成将一个长方形分成n+1个区域
用n条总左到右排好序的直线分成将一个长方形分成n+1个区域
给
你
m
个
点
,
统
计
每
个
区
域
内
点
的
个
数
给你m个点,统计每个区域内点的个数
给你m个点,统计每个区域内点的个数
1
<
=
n
,
m
<
=
5
e
3
1<=n,m<=5e3
1<=n,m<=5e3
做法
我
们
考
虑
我们考虑
我们考虑n^2
的
做
法
即
可
,
从
左
到
右
扫
描
每
条
线
的做法即可,从左到右扫描每条线
的做法即可,从左到右扫描每条线
判
断
当
前
点
是
否
在
这
条
线
左
侧
,
在
左
侧
则
计
数
并
b
r
e
a
k
判断当前点是否在这条线左侧,在左侧则计数并break
判断当前点是否在这条线左侧,在左侧则计数并break
代码
#include <stdio.h>
#include <math.h>
#include <iostream>
#include <algorithm>
using namespace std;
#define dbg(x) cout<<#x<<" = "<<x<<endl
const double eps = 1e-8;
const double inf = 1e20;
const double pi = acos(-1.0);
const int maxn = 5005;
const int maxp = 1010;
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;
}
Point operator - (const Point &b) const
{
return Point(x - b.x, y - b.y);
}
double operator ^ (const Point &b) const
{
return x * b.y - y * b.x;
}
};
struct Line
{
Point s, e;
Line() {}
Line(Point _s, Point _e)
{
s = _s, e = _e;
}
int relation(Point p)//判断点与直线的关系,1在左侧,2在右侧,3在直线上
{
int c = sgn( (p - s) ^ (e - s) );
if (c < 0) return 1;
else if (c > 0) return 2;
return 3;
}
};
Line l[maxn];
int sum[maxn];
int main()
{
int n,m;
int flag=0;
double x,y,xa,ya,xb,yb,up,down;
while(scanf("%d",&n)!=EOF)
{
if(n==0) break;
else if(flag==0) flag=1;
else puts("");
for(int i=0; i<=n; i++) sum[i]=0;
scanf("%d%lf%lf%lf%lf",&m,&xa,&ya,&xb,&yb);
for(int i=0;i<n;i++)
{
scanf("%lf%lf",&up,&down);
l[i]=Line(Point(up,ya),Point(down,yb));
}
l[n]=Line(Point(xb,ya),Point(xb,yb));
for(int i=0;i<m;i++)
{
scanf("%lf%lf",&x,&y);
for(int j=0;j<=n;j++)
{
if(l[j].relation(Point(x,y))==2)
{
sum[j]++;
break;
}
}
}
for(int i=0; i<=n; i++) printf("%d: %d\n",i,sum[i]);
}
return 0;
}
计算几何第二题:POJ-2398-Toy Storage
题意
用
n
条
直
线
分
成
将
一
个
长
方
形
分
成
n
+
1
个
区
域
,
给
你
m
个
点
,
统
计
每
个
区
域
内
点
的
个
数
用n条直线分成将一个长方形分成n+1个区域,给你m个点,统计每个区域内点的个数
用n条直线分成将一个长方形分成n+1个区域,给你m个点,统计每个区域内点的个数
1
<
=
n
,
m
<
=
1
e
3
1<=n,m<=1e3
1<=n,m<=1e3
做法
我
们
可
以
按
照
n
条
直
线
与
上
界
的
交
点
对
n
条
直
线
排
序
,
之
后
暴
力
扫
描
看
他
在
哪
个
区
域
即
可
。
我们可以按照n条直线与上界的交点对n条直线排序,之后暴力扫描看他在哪个区域即可。
我们可以按照n条直线与上界的交点对n条直线排序,之后暴力扫描看他在哪个区域即可。
代码
#include <stdio.h>
#include <math.h>
#include <iostream>
#include <algorithm>
using namespace std;
#define dbg(x) cout<<#x<<" = "<<x<<endl
const double eps = 1e-8;
const double inf = 1e20;
const double pi = acos(-1.0);
const int maxn = 5005;
const int maxp = 1010;
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;
}
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);
}
double operator ^ (const Point &b) const
{
return x * b.y - y * b.x;
}
};
struct Line
{
Point s, e;
Line() {}
Line(Point _s, Point _e)
{
s = _s, e = _e;
}
bool operator <(const Line &b) const
{
if(s==b.s) return e<b.e;
return s<b.s;
}
int relation(Point p)//判断点与直线的关系,1在左侧,2在右侧,3在直线上
{
int c = sgn( (p - s) ^ (e - s) );
if (c < 0) return 1;
else if (c > 0) return 2;
return 3;
}
};
Line l[maxn];
int sum[maxn];
int ans[maxn];
int main()
{
int n,m;
double x,y,xa,ya,xb,yb,up,down;
while(scanf("%d",&n)!=EOF)
{
if(n==0) break;
scanf("%d%lf%lf%lf%lf",&m,&xa,&ya,&xb,&yb);
for(int i=0;i<=max(n,m); i++)
{
sum[i]=0;
ans[i]=0;
}
for(int i=0;i<n;i++)
{
scanf("%lf%lf",&up,&down);
l[i]=Line(Point(up,ya),Point(down,yb));
}
l[n]=Line(Point(xb,ya),Point(xb,yb));
sort(l,l+1+n);
for(int i=0;i<m;i++)
{
scanf("%lf%lf",&x,&y);
for(int j=0;j<=n;j++)
{
if(l[j].relation(Point(x,y))==2)
{
sum[j]++;
break;
}
}
}
for(int i=0;i<=n;i++) ans[sum[i]]++;
printf("Box\n");
for(int i=1;i<=n;i++) if(ans[i]) printf("%d: %d\n",i,ans[i]);
}
return 0;
}
计算几何第三题:POJ-3304-Segments
题意
给
你
n
条
线
段
,
求
是
否
有
一
条
直
线
,
满
足
所
有
直
线
在
其
上
面
的
投
影
有
公
共
的
交
点
给你n条线段,求是否有一条直线,满足所有直线在其上面的投影有公共的交点
给你n条线段,求是否有一条直线,满足所有直线在其上面的投影有公共的交点
1
<
=
n
<
=
100
1<=n<=100
1<=n<=100
做法
首
先
如
果
投
影
有
公
共
的
交
点
,
那
么
如
果
在
那
个
公
共
的
交
点
上
做
垂
线
首先如果投影有公共的交点,那么如果在那个公共的交点上做垂线
首先如果投影有公共的交点,那么如果在那个公共的交点上做垂线
肯
定
会
穿
过
n
条
线
段
,
所
以
我
们
只
要
看
是
否
存
在
一
条
直
线
与
所
有
线
段
都
相
交
即
可
肯定会穿过n条线段,所以我们只要看是否存在一条直线与所有线段都相交即可
肯定会穿过n条线段,所以我们只要看是否存在一条直线与所有线段都相交即可
而
与
这
n
条
线
断
都
相
交
的
直
线
一
定
经
过
某
两
个
线
段
的
端
点
而与这n条线断都相交的直线一定经过某两个线段的端点
而与这n条线断都相交的直线一定经过某两个线段的端点
我
们
假
设
这
条
直
线
不
经
过
任
意
一
个
端
点
,
我
们
一
定
可
以
平
移
这
条
直
线
使
它
达
到
某
个
端
点
再
停
止
我们假设这条直线不经过任意一个端点,我们一定可以平移这条直线使它达到某个端点再停止
我们假设这条直线不经过任意一个端点,我们一定可以平移这条直线使它达到某个端点再停止
之
后
在
那
个
端
点
上
旋
转
使
之
达
到
另
一
个
端
点
停
止
,
也
就
是
说
如
果
存
在
这
样
一
条
直
线
之后在那个端点上旋转使之达到另一个端点停止,也就是说如果存在这样一条直线
之后在那个端点上旋转使之达到另一个端点停止,也就是说如果存在这样一条直线
我
们
只
要
枚
举
所
有
的
两
个
端
点
所
确
定
的
直
线
,
其
中
一
定
会
有
满
足
的
情
况
我们只要枚举所有的两个端点所确定的直线,其中一定会有满足的情况
我们只要枚举所有的两个端点所确定的直线,其中一定会有满足的情况
所
以
我
们
只
要
所以我们只要
所以我们只要O(n^2)
枚
举
所
有
直
线
再
枚举所有直线再
枚举所有直线再o(n)check
是
否
所
有
线
段
都
与
这
条
直
线
相
交
即
可
。
是否所有线段都与这条直线相交即可。
是否所有线段都与这条直线相交即可。
代码
#include <stdio.h>
#include <math.h>
#include <iostream>
#include <algorithm>
using namespace std;
const double eps = 1e-8;
const double inf = 1e20;
const double pi = acos(-1.0);
const int maxn = 1005;
const int maxp = 1010;
int sgn(double x)
{
if (fabs(x) <eps) return 0;
if(x <0) 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("%.2f %.2f\n", 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);
}
double operator ^ (const Point &b) const
{
return x * b.y - y * b.x;
}
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);
}
Point operator + (const Point &b) const
{
return Point(x + b.x, y + b.y);
}
Point operator * (const double &k) const
{
return Point(x * k, y * k);
}
Point operator / (const double &k) const
{
return Point (x / k, y / k);
}
double rad(Point a, Point b)
{
Point p = *this;
return fabs(atan2( fabs((a - p) ^ (b - p)), (a - p) * (b - p) ));
}
Point trunc(double r)
{
double l = len();
if (!sgn(l)) return *this;
r /= l;
return Point(x * r, y * r);
}
};
struct Line
{
Point s, e;
Line() {}
Line(Point _s, Point _e)
{
s = _s, e = _e;
}
bool operator == (Line v)
{
return (s == v.s) && (e == v.e);
}
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)));
}
Line(double a, double b, double c)
{
if (sgn(a) == 0)
{
s = Point(0, -c / b);
e = Point(1, -c / b);
}
else if (sgn(b) == 0)
{
s = Point(-c / a, 0);
e = Point(-c / a, 1);
}
else
{
s = Point(0, -c / b);
e = Point(1, (-c-a) / b);
}
}
void input()
{
s.input();
e.input();
}
void adjust()
{
if (e < s) swap(s, e);
}
double length()
{
return s.distance(e);
}
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;
}
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((p - s) * (p - e)) <= 0;
}
bool parallel(Line v)
{
return sgn((e - s) ^ (v.e - v.s)) == 0;
}
Point lineprog(Point p)
{
return s + ( ((e - s) * ((e - s) * (p - s))) / ((e - s).len2()) );
}
Point symmetrypoint(Point p)
{
Point q = lineprog(p);
return Point(2.0 * q.x - p.x, 2.0 * q.y - p.y);
}
double dispointtoline(Point p)
{
return fabs((p - s) ^ (e - s)) / length();
}
int linecrossseg(Line v)
{
int d1=sgn((e-s)^(v.s-s));
int d2=sgn((e-s)^(v.e-s));
if((d1^d2)==-2) return 2;
return (d1==0||d2==0);
}
};
Point p[maxn];
Line L[maxn];
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
double xa,ya,xb,yb;
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lf%lf%lf%lf",&xa,&ya,&xb,&yb);
p[i]=Point(xa,ya);
p[i+n]=Point(xb,yb);
L[i]=Line(p[i],p[i+n]);
}
int ff=0;
for(int i=1;i<=2*n;i++)
{
for(int j=i;j<=2*n;j++)
{
if(p[i]==p[j]) continue;//防止出现两个点重合的情况
Line now(p[i],p[j]);
int flag=0;
for(int k=1;k<=n;k++)
{
if(now.linecrossseg(L[k])==0)
{
flag=1;
break;
}
}
if(flag==0)
{
ff=1;
break;
}
}
if(ff==1) break;
}
if(ff==1) puts("Yes!");
else puts("No!");
}
return 0;
}
计算几何第四题:POJ-1269-Intersecting Lines
题意
给
你
一
对
直
线
,
判
断
两
条
位
置
关
系
给你一对直线,判断两条位置关系
给你一对直线,判断两条位置关系
做法
先
用
叉
积
判
断
两
条
直
线
是
否
平
行
先用叉积判断两条直线是否平行
先用叉积判断两条直线是否平行
如
果
不
平
行
则
是
相
交
,
平
行
的
话
判
一
下
一
条
直
线
上
的
点
是
否
在
另
一
条
直
线
上
如果不平行则是相交,平行的话判一下一条直线上的点是否在另一条直线上
如果不平行则是相交,平行的话判一下一条直线上的点是否在另一条直线上
若
在
则
是
重
合
,
不
在
则
是
平
行
,
。
若在则是重合,不在则是平行,。
若在则是重合,不在则是平行,。
代码
#include <stdio.h>
#include <math.h>
#include <iostream>
#include <algorithm>
using namespace std;
const double eps = 1e-12;
const double inf = 1e20;
const double pi = acos(-1.0);
const int maxp = 1010;
int sgn( double x) {
if (fabs(x) <eps) return 0;
if(x <0) 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() {cout << x << " " << y << endl; }
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);}
double operator ^ (const Point &b) const {return x * b.y - y * b.x;}
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);}
Point operator + (const Point &b) const {return Point(x + b.x, y + b.y);}
Point operator * (const double &k) const {return Point(x * k, y * k);}
Point operator / (const double &k) const {return Point (x / k, y / k);}
double rad(Point a, Point b) {
Point p = *this;
return fabs(atan2( fabs((a - p) ^ (b - p)), (a - p) * (b - p) ));
}
Point trunc(double r) {
double l = len();
if (!sgn(l)) return *this;
r /= l;
return Point(x * r, y * r);
}
};
struct Line {
Point s, e;
Line() {}
Line(Point _s, Point _e) {s = _s, e = _e;}
bool operator == (Line v) {return (s == v.s) && (e == v.e);}
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)));
}
Line(double a, double b, double c) {
if (sgn(a) == 0) {
s = Point(0, -c / b);
e = Point(1, -c / b);
}
else if (sgn(b) == 0) {
s = Point(-c / a, 0);
e = Point(-c / a, 1);
}
else {
s = Point(0, -c / b);
e = Point(1, (-c-a) / b);
}
}
Point getV() {return e-s;}
void input() {s.input(); e.input();}
void adjust() {if (e < s) swap(s, e);}
double length() {return s.distance(e);}
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;
}
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((p - s) * (p - e)) <= 0;
}
bool parallel(Line v) {return sgn((e - s) ^ (v.e - v.s)) == 0;}
Point lineprog(Point p) {
return s + ( ((e - s) * ((e - s) * (p - s))) / ((e - s).len2()) );
}
Point symmetrypoint(Point p) {
Point q = lineprog(p);
return Point(2.0 * q.x - p.x, 2.0 * q.y - p.y);
}
double dispointtoline(Point p) {return fabs((p - s) ^ (e - s)) / length();}
double dispointtoseg(Point p) {
if (sgn((p-s)*(e-s))<0 || sgn((p-e)*(s-e))<0)
return min(p.distance(s), p.distance(e));
return dispointtoline(p);
}
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);
double 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));
}
};
int main()
{
int n;
double xa,xb,ya,yb,xc,yc,xd,yd;
while(scanf("%d",&n)!=EOF)
{
printf("INTERSECTING LINES OUTPUT\n");
while(n--)
{
scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&xa,&ya,&xb,&yb,&xc,&yc,&xd,&yd);
Line L1(Point(xa,ya),Point(xb,yb));
Line L2(Point(xc,yc),Point(xd,yd));
int tmp=L1.linecrossline(L2);
if(tmp==0) printf("NONE\n");
else if(tmp==1) printf("LINE\n");
else
{
Point ans=L1.crosspoint(L2);
printf("POINT %.2f %.2f\n",ans.x,ans.y);
}
}
printf("END OF OUTPUT\n");
}
}
计算几何第五题:POJ-1556-The Doors
题意
一
个
房
间
内
有
平
行
的
n
堵
墙
,
每
个
墙
上
有
两
道
门
,
求
从
起
点
走
到
终
点
的
最
短
路
径
。
一个房间内有平行的n堵墙,每个墙上有两道门,求从起点走到终点的最短路径。
一个房间内有平行的n堵墙,每个墙上有两道门,求从起点走到终点的最短路径。
例如下图:
做法
可
以
到
某
个
门
的
最
短
距
离
一
定
是
由
某
个
门
的
两
端
点
出
发
的
可以到某个门的最短距离一定是由某个门的两端点出发的
可以到某个门的最短距离一定是由某个门的两端点出发的
所
以
我
们
只
要
从
左
到
右
算
出
到
达
每
个
点
的
最
短
距
离
所以我们只要从左到右算出到达每个点的最短距离
所以我们只要从左到右算出到达每个点的最短距离
每
个
点
用
所
有
之
前
可
以
直
接
到
达
这
个
点
的
点
去
松
弛
这
个
点
,
复
杂
度
O
(
n
3
)
每个点用所有之前可以直接到达这个点的点去松弛这个点,复杂度O(n^3)
每个点用所有之前可以直接到达这个点的点去松弛这个点,复杂度O(n3)
代码
#include <stdio.h>
#include <math.h>
#include <iostream>
#include <algorithm>
using namespace std;
const double eps = 1e-12;
const double inf = 1e20;
const double pi = acos(-1.0);
const int maxp = 1010;
int sgn( double x)
{
if (fabs(x) <eps) return 0;
if(x <0) 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()
{
cout <<"x= "<<x << " y= " << y << endl;
}
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);
}
//叉积 |a||b|sin
double operator ^ (const Point &b) const
{
return x * b.y - y * b.x;
}
//点积 |a||b|cos 向量点积之后反过来求夹角
double operator * (const Point & b) const
{
return x * b.x + y * b.y;
}
//利用库函数计算点到(0,0)的距离
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);
}
//向量加法
Point operator + (const Point &b) const
{
return Point(x + b.x, y + b.y);
}
//向量乘常数
Point operator * (const double &k) const
{
return Point(x * k, y * k);
}
//向量除以常数
Point operator / (const double &k) const
{
return Point (x / k, y / k);
}
//求a,b以当前点为中间点的角
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);
}
};
struct Line
{
Point s, e;
Line() {}
Line(Point _s, Point _e)
{
s = _s, e = _e;
}
//直线判断重合
bool operator == (Line v)
{
return (s == v.s) && (e == v.e);
}
//根据一个点和倾斜角angle确定直线,0<=angle<pi
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确定直线
Line(double a, double b, double c)
{
if (sgn(a) == 0)
{
s = Point(0, -c / b);
e = Point(1, -c / b);
}
else if (sgn(b) == 0)
{
s = Point(-c / a, 0);
e = Point(-c / a, 1);
}
else
{
s = Point(0, -c / b);
e = Point(1, (-c-a) / b);
}
}
//得到s-e方向单位向量
Point getV()
{
return e-s;
}
void input()
{
s.input();
e.input();
}
void adjust()
{
if (e < s) swap(s, e);
}
//返回线段的长度
double length()
{
return s.distance(e);
}
//返回直线倾斜角
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((p - s) * (p - e)) <= 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));
int d2 = sgn((e-s)^(v.e-s));
int d3 = sgn((v.e-v.s)^(s-v.s));
int 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));
}
Point lineprog(Point p)
{
return s + ( ((e - s) * ((e - s) * (p - s))) / ((e - s).len2()) );
}
Point symmetrypoint(Point p)
{
Point q = lineprog(p);
return Point(2.0 * q.x - p.x, 2.0 * q.y - p.y);
}
double dispointtoline(Point p)
{
return fabs((p - s) ^ (e - s)) / length();
}
double dispointtoseg(Point p)
{
if (sgn((p-s)*(e-s))<0 || sgn((p-e)*(s-e))<0)
return min(p.distance(s), p.distance(e));
return dispointtoline(p);
}
//两直线关系
//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);
double 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));
}
};
const int maxn = 1005;
double dp[maxn];
Line seg[maxn];
Point p[maxn];
int pcnt,lcnt;
int main()
{
double x,ya,yb,yc,yd;
int n;
while(scanf("%d",&n)!=EOF)
{
if(n==-1) break;
pcnt=0,lcnt=0;
p[++pcnt]=Point(0,5);
for(int i=1;i<=n;i++)
{
scanf("%lf%lf%lf%lf%lf",&x,&ya,&yb,&yc,&yd);
p[++pcnt]=Point(x,ya);
p[++pcnt]=Point(x,yb);
p[++pcnt]=Point(x,yc);
p[++pcnt]=Point(x,yd);
seg[++lcnt]=Line(Point(x,0),Point(x,ya));
seg[++lcnt]=Line(Point(x,yb),Point(x,yc));
seg[++lcnt]=Line(Point(x,yd),Point(x,10));
}
p[++pcnt]=Point(10,5);
dp[1]=0.0;
for(int i=2;i<=pcnt;i++) dp[i]=1e20;
for(int i=2;i<=pcnt;i++)
{
for(int j=1;j<i;j++)
{
Line tmp(p[i],p[j]);
int flag=0;
for(int k=1;k<=(i-2)/4*3;k++)//对所有在这个点左边的线段判交,有交点则不能松弛
{
if(seg[k].segcrossseg(tmp)==2)
{
flag=1;
break;
}
}
if(flag==0) dp[i]=min(dp[i],dp[j]+tmp.length());
}
}
printf("%.2f\n",dp[pcnt]);
}
}
计算几何第六题NWERC2017-Problem G-Glyph Recognition
题意
给
你
n
个
点
,
找
出
一
种
中
心
在
远
点
而
且
有
一
个
点
在
x
轴
上
的
正
多
边
形
环
覆
盖
这
些
点
给你n个点,找出一种中心在远点而且有一个点在x轴上的正多边形环覆盖这些点
给你n个点,找出一种中心在远点而且有一个点在x轴上的正多边形环覆盖这些点
(
在
一
个
正
多
边
形
中
扣
去
一
个
与
他
相
似
的
且
平
行
的
正
多
边
形
)
(在一个正多边形中扣去一个与他相似的且平行的正多边形)
(在一个正多边形中扣去一个与他相似的且平行的正多边形)
使
这
个
环
的
外
围
面
积
尽
量
小
,
内
围
面
积
尽
量
大
使这个环的外围面积尽量小,内围面积尽量大
使这个环的外围面积尽量小,内围面积尽量大
正
多
边
形
为
正
3
−
8
边
形
,
求
内
部
面
积
与
外
部
面
积
的
最
大
比
值
正多边形为正3-8边形,求内部面积与外部面积的最大比值
正多边形为正3−8边形,求内部面积与外部面积的最大比值
做法
二
分
每
种
正
多
边
形
在
x
轴
上
点
的
横
坐
标
二分每种正多边形在x轴上点的横坐标
二分每种正多边形在x轴上点的横坐标
当
计
算
最
大
的
内
围
面
积
时
,
只
要
当
前
多
边
形
内
不
包
含
点
就
可
以
变
大
当计算最大的内围面积时,只要当前多边形内不包含点就可以变大
当计算最大的内围面积时,只要当前多边形内不包含点就可以变大
当
计
算
最
小
的
外
围
面
积
时
,
只
要
当
前
多
边
形
内
有
n
个
点
就
可
以
减
小
当计算最小的外围面积时,只要当前多边形内有n个点就可以减小
当计算最小的外围面积时,只要当前多边形内有n个点就可以减小
二
分
计
算
每
种
多
边
形
的
答
案
取
m
a
x
即
可
二分计算每种多边形的答案取max即可
二分计算每种多边形的答案取max即可
构
造
多
边
形
用
点
根
据
原
点
旋
转
一
定
度
数
来
做
构造多边形用点根据原点旋转一定度数来做
构造多边形用点根据原点旋转一定度数来做
判
一
个
点
是
否
在
多
边
形
内
部
只
需
判
定
他
在
这
个
多
边
形
所
有
向
量
的
左
侧
即
可
。
判一个点是否在多边形内部只需判定他在这个多边形所有向量的左侧即可。
判一个点是否在多边形内部只需判定他在这个多边形所有向量的左侧即可。
代码
#include<iomanip>
#include<iostream>
#include<math.h>
using namespace std;
const long double eps= 1e-9;
const long double pi = acos(-1.0);
int sgn(long double x)
{
if(fabs(x)<eps) return 0;
if(x<0) return -1;
else return 1;
}
struct Point
{
long double x,y;
Point(){}
Point (long double _x,long double _y)
{
x=_x,y=_y;
}
Point operator -(const Point &b)const
{
return Point(x-b.x,y-b.y);
}
long double operator ^(const Point &b) const
{
return x*b.y-y*b.x;
}
Point rotat(Point p,double angle)
{
Point v=(*this)-p;
double c=cos(angle),s=sin(angle);
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;
}
int relation(Point p)
{
int c=sgn((p-s)^(e-s));
if(c<0) return 1;
else if(c>0) return 2;
else return 3;
}
};
const int maxn = 1005;
int n;
Point p[maxn],pp[maxn];
Line l[maxn];
int check(long double mid,int pos)
{
long double ang=2.0*pi/(1.0*pos);
pp[0]=Point(mid,0.0);
for(int i=1;i<pos;i++) pp[i]=pp[i-1].rotat(Point(0,0),ang);//旋转获得每个点
for(int i=0;i<pos-1;i++) l[i]=Line (pp[i],pp[i+1]);//按逆时针建边
l[pos-1]=Line(pp[pos-1],pp[0]);
int cnt=0;
for(int i=1;i<=n;i++)
{
int flag=0;
for(int j=0;j<pos;j++) if(l[j].relation(p[i])!=1){flag=1;break;}
if(flag==0) cnt++;
}
return cnt;
}
int main()
{
ios::sync_with_stdio(false);
int pos;
long double up,ans=0;
cin>>n;
for(int i=1;i<=n;i++) cin>>p[i].x>>p[i].y;
for(int i=3;i<=8;i++)
{
long double l=0,r=1e10;
while(r-l>=eps)
{
long double mid=(l+r)/2.0;
if(check(mid,i)==0) l=mid;
else r=mid;
}
up=l*l,l=0,r=1e10;
while(r-l>=eps)
{
long double mid=(l+r)/2.0;
if(check(mid,i)==n) r=mid;
else l=mid;
}
if(up/(l*l)>ans) ans=up/(l*l),pos=i;
}
cout<<pos<<" "<<fixed<<setprecision(10)<<ans<<endl;
return 0;
}
计算几何第七题POJ-2653-Pick-up sticks
题意
在
一
个
二
维
平
面
上
依
次
放
置
n
条
木
棍
,
问
最
后
没
有
被
覆
盖
的
木
棍
有
哪
些
,
n
<
=
1
e
5
,
答
案
<
=
1000
在一个二维平面上依次放置n条木棍,问最后没有被覆盖的木棍有哪些,n<=1e5,答案<=1000
在一个二维平面上依次放置n条木棍,问最后没有被覆盖的木棍有哪些,n<=1e5,答案<=1000
做法
我
们
时
光
倒
流
一
下
,
从
后
往
前
做
这
道
题
我们时光倒流一下,从后往前做这道题
我们时光倒流一下,从后往前做这道题
很
明
显
最
后
一
根
木
棍
一
定
是
在
最
上
面
的
,
那
么
这
条
木
棍
所
覆
盖
的
木
棍
一
定
都
是
被
覆
盖
的
很明显最后一根木棍一定是在最上面的,那么这条木棍所覆盖的木棍一定都是被覆盖的
很明显最后一根木棍一定是在最上面的,那么这条木棍所覆盖的木棍一定都是被覆盖的
依
次
递
推
就
能
求
出
所
有
被
最
后
一
条
木
棍
直
接
覆
盖
或
者
间
接
覆
盖
的
木
棍
依次递推就能求出所有被最后一条木棍直接覆盖或者间接覆盖的木棍
依次递推就能求出所有被最后一条木棍直接覆盖或者间接覆盖的木棍
然
后
继
续
向
前
扫
描
到
一
个
没
有
被
覆
盖
的
木
棍
,
然
后
重
复
这
个
过
程
然后继续向前扫描到一个没有被覆盖的木棍,然后重复这个过程
然后继续向前扫描到一个没有被覆盖的木棍,然后重复这个过程
这
样
就
可
以
得
到
所
有
在
最
顶
层
的
木
棍
,
如
果
我
们
用
v
i
s
标
记
被
覆
盖
木
棍
的
方
法
这样就可以得到所有在最顶层的木棍,如果我们用vis标记被覆盖木棍的方法
这样就可以得到所有在最顶层的木棍,如果我们用vis标记被覆盖木棍的方法
时
间
复
杂
度
为
n
2
时间复杂度为n^2
时间复杂度为n2
但
是
如
果
我
们
用
l
i
s
t
里
面
的
l
i
s
t
维
护
没
有
被
覆
盖
的
木
棍
,
时
间
复
杂
度
就
是
O
(
n
∗
1000
)
。
但是如果我们用list里面的list维护没有被覆盖的木棍,时间复杂度就是O(n*1000)。
但是如果我们用list里面的list维护没有被覆盖的木棍,时间复杂度就是O(n∗1000)。
代码
#include<stdio.h>
#include<math.h>
#include<queue>
#include<list>
#include<iostream>
#include<algorithm>
using namespace std;
const double eps = 1e-12;
const double pi = acos(-1.0);
const int maxp = 1010;
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;
}
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);
}
//叉积 |a||b|sin
double operator ^ (const Point &b) const
{
return x * b.y - y * b.x;
}
//点积 |a||b|cos 向量点积之后反过来求夹角
double operator * (const Point & b) const
{
return x * b.x + y * b.y;
}
Point operator + (const Point &b) const
{
return Point(x + b.x, y + b.y);
}
};
struct Line
{
Point s, e;
Line() {}
Line(Point _s, Point _e)
{
s = _s, e = _e;
}
//两线段相交判断
//2 规范相交
//1 非规范相交-过端点
//0 不相交
int segcrossseg(Line v)
{
int d1 = sgn((e-s)^(v.s-s));
int d2 = sgn((e-s)^(v.e-s));
int d3 = sgn((v.e-v.s)^(s-v.s));
int 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));
}
};
const int maxn = 1e5+10;
Line l[maxn];
vector<int>ans;
list<int> L;
void del(list<int>::iterator it)//递归算出所有被当前线段所影响的线段
{
Line now = l[*it];
list<int>::iterator tmp=it;
for(list<int>::iterator itt=(++it);itt!=L.end();)
{
Line nex = l[*itt];
if(now.segcrossseg(nex))
{
del(itt);//找到之后先递归,再将本点删除
itt=L.erase(itt);
}
else ++itt;
}
return ;
}
int main()
{
int n;
double xa,xb,ya,yb;
while(scanf("%d",&n)!=EOF)
{
L.clear();
ans.clear();
if(n==0) break;
for(int i=1;i<=n;i++)
{
scanf("%lf%lf%lf%lf",&xa,&ya,&xb,&yb);
l[i]=Line (Point(xa,ya),Point(xb,yb));
}
for(int i=n;i>=1;i--)
{
L.push_back(i);
}
for(list<int>::iterator it=L.begin();it!=L.end();)
{
list<int>::iterator tmp=it;
del(it);
it=++tmp;//由于有删除操作,要先存当前指针位置,在删除之后让迭代器指向当前的下一位
}
L.reverse();
for(list<int>::iterator it=L.begin();it!=L.end();++it)
{
int tmp=*it;
ans.push_back(tmp);
}
sort(ans.begin(),ans.end());//保证答案有序
printf("Top sticks:");
for(int i=0;i<ans.size();i++)
{
if(i!=ans.size()-1) printf(" %d,",ans[i]);
else printf(" %d.\n",ans[i]);
}
}
return 0;
}