Training:计算几何基础

计算几何基础部分大部分题目只要有模板就能过了,下面的题也大都是贴模板过的。

HDU 1086:
http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=17612
给出 n 条线段,求其中相交的对数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include<cstdio>
struct Line{
double x1,y1,x2,y2;
}a[110];
bool solve(Line a,Line b){
if(((a.x1-b.x1)*(a.y2-b.y1)-(a.x2-b.x1)*(a.y1-b.y1))*((a.x1-b.x2)*(a.y2-b.y2)-(a.x2-b.x2)*(a.y1-b.y2))>0)return false;
if(((b.x1-a.x1)*(b.y2-a.y1)-(b.x2-a.x1)*(b.y1-a.y1))*((b.x1-a.x2)*(b.y2-a.y2)-(b.x2-a.x2)*(b.y1-a.y2))>0)return false;
return true;
}
int main(){
int n;
while(~scanf("%d",&n)&&n){
int cnt=0;
for(int i=0;i<n;++i)
scanf("%lf%lf%lf%lf",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2);
for(int i=0;i<n;++i)
for(int j=i+1;j<n;++j)
if(solve(a[i],a[j]))
++cnt;
printf("%d\n",cnt);
}
return 0;
}

HDU 1115:
http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=16214
按顺序给出多个点,求给出点的的重心坐标。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include<cstdio>
using namespace std;
const int maxn=1000010;
struct node{
double x,y;
}a[maxn];
node gravity(node *p, int n)
{
double area = 0;
node center;
center.x = 0;
center.y = 0;
for (int i = 0; i < n-1; i++)
{
area += (p[i].x*p[i+1].y - p[i+1].x*p[i].y)/2;
center.x += (p[i].x*p[i+1].y - p[i+1].x*p[i].y) * (p[i].x + p[i+1].x);
center.y += (p[i].x*p[i+1].y - p[i+1].x*p[i].y) * (p[i].y + p[i+1].y);
}
area += (p[n-1].x*p[0].y - p[0].x*p[n-1].y)/2;
center.x += (p[n-1].x*p[0].y - p[0].x*p[n-1].y) * (p[n-1].x + p[0].x);
center.y += (p[n-1].x*p[0].y - p[0].x*p[n-1].y) * (p[n-1].y + p[0].y);
center.x /= 6*area;
center.y /= 6*area;
return center;
}
int main(){
int t;scanf("%d",&t);
while(t--){
int n;scanf("%d",&n);
for(int i=0;i<n;++i)
scanf("%lf%lf",&a[i].x,&a[i].y);
node ans=gravity(a,n);
printf("%.2lf %.2lf\n",ans.x,ans.y);
}
return 0;
}

HDU 2036:
http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=17490
按顺序给出多个点的坐标,求所构成的凸多边形面积。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include<cstdio>
#include<cmath>
const int maxn=110;
struct point{
double x,y;
}a[maxn];
double area_polygon(int n,point* p){
double s1=0,s2=0;
for(int i=0;i<n;++i)
s1+=p[(i+1)%n].y*p[i].x,s2+=p[(i+1)%n].y*p[(i+2)%n].x;
return fabs(s1-s2)/2;
}
int main(){
int n;
while(~scanf("%d",&n)&&n){
for(int i=0;i<n;++i)
scanf("%lf%lf",&a[i].x,&a[i].y);
printf("%.1lf\n",area_polygon(n,a));
}
return 0;
}

HDU 2108:
http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=18631
按顺序给出多个点,判断形成的是凸多边形,还是凹多边形。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include<cstdio>
#include<cmath>
const int maxn=110;
struct point{
double x,y;
}a[maxn];
#define eps 1e-8
#define _sign(x) ((x)>eps?1:((x)<-eps?2:0))
double xmult(point p1,point p2,point p0){
return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
int is_convex(int n,point* p){
int i,s[3]={1,1,1};
for (i=0;i<n&&s[1]|s[2];i++)
s[_sign(xmult(p[(i+1)%n],p[(i+2)%n],p[i]))]=0; return s[1]|s[2];
}
int main(){
int n;
while(~scanf("%d",&n)&&n){
for(int i=0;i<n;++i)
scanf("%lf%lf",&a[i].x,&a[i].y);
puts(is_convex(n,a)?"convex":"concave");
}
return 0;
}

HDU 1392:
http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=18630
给出多个点,求凸包的周长。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=110;
struct point{
double x,y;
}a[maxn],b[maxn];
bool mult(point p0,point p1,point p2){
return (p1.x-p0.x)*(p2.y-p0.y)>=(p2.x-p0.x)*(p1.y-p0.y);
}
bool operator<(const point &p1,const point &p2){
return p1.y<p2.y||(p1.y==p2.y&&p1.x<p2.x);
}
int graham(point pnt[],int n,point res[]){
int i,len,top=1;
sort(pnt,pnt+n);
if(n==0) return 0;
res[0]=pnt[0];
if(n==1) return 1;
res[1]=pnt[1];
if(n==2) return 2;
res[2]=pnt[2];
for(i=2;i<n;i++){
while(top&&mult(pnt[i],res[top],res[top-1]))
top--;
res[++top]=pnt[i];
}
len=top;res[++top]=pnt[n-2];
for(i=n-3;i>=0;i--){
while(top!=len&&mult(pnt[i],res[top],res[top-1]))
top--;
res[++top]=pnt[i];
}
return top;
}
int main(){
int n;
while(~scanf("%d",&n)&&n){
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for(int i=0;i<n;++i) scanf("%lf%lf",&a[i].x,&a[i].y);
int k=graham(a,n,b);
double ans=0;
for(int i=0;i<k-1;++i)
ans+=sqrt((b[i].x-b[i+1].x)*(b[i].x-b[i+1].x)+(b[i].y-b[i+1].y)*(b[i].y-b[i+1].y));
if(k>2) ans+=sqrt((b[k-1].x-b[0].x)*(b[k-1].x-b[0].x)+(b[k-1].y-b[0].y)*(b[k-1].y-b[0].y));
printf("%.2lf\n",ans);
}
return 0;
}

HDU 1348:
http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=32007
求凸包每个顶点向外延伸半径为1的圆后所得图形的周长。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=1010;
struct point{
double x,y;
}a[maxn],b[maxn];
bool mult(point p0,point p1,point p2){
return (p1.x-p0.x)*(p2.y-p0.y)>=(p2.x-p0.x)*(p1.y-p0.y);
}
bool operator<(const point &p1,const point &p2){
return p1.y<p2.y||(p1.y==p2.y&&p1.x<p2.x);
}
int graham(point pnt[],int n,point res[]){
int i,len,top=1;
sort(pnt,pnt+n);
if(n==0) return 0;
res[0]=pnt[0];
if(n==1) return 1;
res[1]=pnt[1];
if(n==2) return 2;
res[2]=pnt[2];
for(i=2;i<n;i++){
while(top&&mult(pnt[i],res[top],res[top-1]))
top--;
res[++top]=pnt[i];
}
len=top;res[++top]=pnt[n-2];
for(i=n-3;i>=0;i--){
while(top!=len&&mult(pnt[i],res[top],res[top-1]))
top--;
res[++top]=pnt[i];
}
return top;
}
int main(){
int t;scanf("%d",&t);
while(t--){
int n,l;scanf("%d%d",&n,&l);
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for(int i=0;i<n;++i) scanf("%lf%lf",&a[i].x,&a[i].y);
int k=graham(a,n,b);
double ans=0;
for(int i=0;i<k-1;++i)
ans+=sqrt((b[i].x-b[i+1].x)*(b[i].x-b[i+1].x)+(b[i].y-b[i+1].y)*(b[i].y-b[i+1].y));
if(k>2) ans+=sqrt((b[k-1].x-b[0].x)*(b[k-1].x-b[0].x)+(b[k-1].y-b[0].y)*(b[k-1].y-b[0].y));
ans+=2*acos(-1)*l;
printf("%.0lf\n",ans);
if(t) printf("\n");
}
return 0;
}

HDU 2150:
http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=31178
给出多条线段,判断有无相交线段。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include<cstdio>
struct Line{
double x1,y1,x2,y2;
Line(double x1=0,double y1=0,double x2=0,double y2=0):x1(x1),y1(y1),x2(x2),y2(y2){}
};
struct node{
int k;
Line l[110];
}a[33];
bool solve(Line a,Line b){
if(((a.x1-b.x1)*(a.y2-b.y1)-(a.x2-b.x1)*(a.y1-b.y1))*((a.x1-b.x2)*(a.y2-b.y2)-(a.x2-b.x2)*(a.y1-b.y2))>0)return false;
if(((b.x1-a.x1)*(b.y2-a.y1)-(b.x2-a.x1)*(b.y1-a.y1))*((b.x1-a.x2)*(b.y2-a.y2)-(b.x2-a.x2)*(b.y1-a.y2))>0)return false;
return true;
}
int main(){
int n;
while(~scanf("%d",&n)){
for(int i=0;i<n;++i){
scanf("%d",&a[i].k);
--a[i].k;
double px1,py1;
scanf("%lf%lf",&px1,&py1);
for(int j=0;j<a[i].k;++j){
double x1,y1;
scanf("%lf%lf",&x1,&y1);
a[i].l[j]=Line(px1,py1,x1,y1);
px1=x1,py1=y1;
}
}
bool flag=false;
for(int i=0;i<n;++i)
for(int j=i+1;j<n;++j)
for(int k=0;k<a[i].k;++k)
for(int l=0;l<a[j].k;++l)
if(solve(a[i].l[k],a[j].l[l])) {flag=true;goto END;}
END:
printf("%s\n",flag?"Yes":"No");
}
return 0;
}

HDU 1558:
http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=19356
给出多条线段,输出有几个连通块。判断线段相交之后,用并查集求解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include<iostream>
#include<string>
using namespace std;
const int maxn=1010;
int p[maxn],num[maxn];
struct Line{
double x1,y1,x2,y2;
Line(double x1=0,double y1=0,double x2=0,double y2=0):x1(x1),y1(y1),x2(x2),y2(y2){}
}a[maxn];
//有模板就是好!!!
bool solve(Line a,Line b){
if(((a.x1-b.x1)*(a.y2-b.y1)-(a.x2-b.x1)*(a.y1-b.y1))*((a.x1-b.x2)*(a.y2-b.y2)-(a.x2-b.x2)*(a.y1-b.y2))>0)return false;
if(((b.x1-a.x1)*(b.y2-a.y1)-(b.x2-a.x1)*(b.y1-a.y1))*((b.x1-a.x2)*(b.y2-a.y2)-(b.x2-a.x2)*(b.y1-a.y2))>0)return false;
return true;
}
int find(int x){
return p[x]==x?x:p[x]=find(p[x]);
}
void merge(int x,int y){
int fx=find(x),fy=find(y);
if(fx!=fy) p[fx]=fy,num[fy]+=num[fx];
return;
}
int main(){
int t;cin>>t;
while(t--){
int n,cnt=0;cin>>n;
for(int i=0;i<n;++i){
string s;cin>>s;
if(s=="P"){
++cnt,p[cnt]=cnt,num[cnt]=1;
Line& k=a[cnt];
cin>>k.x1>>k.y1>>k.x2>>k.y2;
for(int j=1;j<cnt;++j){
if(find(j)!=find(cnt)&&solve(a[j],k))
merge(cnt,j);
}
}
else if(s=="Q"){
int k;cin>>k;
cout<<num[find(k)]<<endl;
}
}
if(t) cout<<endl;
}
return 0;
}

HDU 1785:
http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=30271
就是结构体重载运算符的题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<cstdio>
#include<algorithm>
const int maxn=110;
struct node{
double x,y;
bool operator < (const node& rhs) const {
return x*rhs.y>rhs.x*y;
}
}a[maxn];
int main(){
int n;
while(~scanf("%d",&n)&&n>=0){
for(int i=0;i<n;++i) scanf("%lf%lf",&a[i].x,&a[i].y);
std::sort(a,a+n);
for(int i=0;i<n;++i) printf("%.1lf %.1lf%c",a[i].x,a[i].y,i==n-1?'\n':' ');
}
return 0;
}

** 本文迁移自我的CSDN博客,格式可能有所偏差。 **