计算几何题目总结

计算几何题目总结

1、线段交+最短路 POJ1556

总共4*n+1个点。
根据线段交去判断会不会冲突,可以直接连的就建立一条路径。
然后求最短路。
因为点很小,所以无论哪种最短路算法都可使用。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const double INF = 1e8;
const double eps = 1e-8;
const int maxn = 1e3 + 10;
double d[maxn][maxn];
struct point {
    double x, y;
    point() {}
    point(double x, double y): x(x), y(y) {};
    point operator - (const point & a) const {
        return point(x - a.x, y - a.y);
    }
    double operator * (const point & a) const {
        return x * a.x + y * a.y;
    }
} p[maxn];
double dist(point a, point b) {
    return sqrt((a - b) * (a - b));
}
double cross(point a, point b) {
    return a.x * b.y - b.x * a.y;
}
int judge(point p1, point p2, point q1, point q2) {
    double cros1 = cross(q1 - p1, q2 - p1);
    double cros2 = cross(q1 - p2, q2 - p2);
    if (fabs(cros1) < eps || fabs(cros2) < eps) return 1;
    return cros1 * cros2 < 0 ? 1 : 0  ;
}

int main() {
    int n;
    while(scanf("%d", &n) && n != -1) {
        p[0] = point(0, 5);
        double x, y1, y2, y3, y4;
        for (int i = 0 ; i < n ; i++) {
            scanf("%lf%lf%lf%lf%lf", &x, &y1, &y2, &y3, &y4);
            p[i * 4 + 1] = point(x, y1);
            p[i * 4 + 2] = point(x, y2);
            p[i * 4 + 3] = point(x, y3);
            p[i * 4 + 4] = point(x, y4);
        }
        p[n * 4 + 1] = point(10, 5);
        memset(d, 0, sizeof(d));
        for (int i = 0 ; i <= 4 * n + 1 ; i++) {
            for (int j = i + 1 ; j <= 4 * n + 1 ; j++) {
                int l = (i - 1) / 4, r = (j - 1) / 4;
                if (i == 0) l = -1;
                int flag = 1;
                for (int k = l + 1 ; k < r ; k++) {
                    if (judge(p[4 * k + 1], point(p[4 * k + 1].x, 0), p[i], p[j])) {
                        flag = 0;
                        break;
                    }
                    if (judge(p[4 * k + 2], p[4 * k + 3], p[i], p[j])) {
                        flag = 0;
                        break;
                    }
                    if (judge(p[4 * k + 4], point(p[4 * k + 4].x, 10), p[i], p[j])) {
                        flag = 0;
                        break;
                    }
                }
                d[i][j] = d[j][i] = (flag ?  dist(p[i], p[j]) : INF) ;
            }
        }
        for (int k = 0 ; k <= 4 * n + 1 ; k++)
            for (int i = 0 ; i <= 4 * n + 1 ; i++)
                for (int j = 0 ; j <= 4 * n + 1 ; j++)
                    d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
        printf("%.2f\n", d[0][4 * n + 1]);
    }
    return 0;
}

2、极角排序 POJ1696

极角排序:
在平面内取一个定点O,叫极点,引一条射线Ox,叫做极轴,再选定一个长度单位和角度的正方向(通常取逆时针方向)。
对于平面内任何一点M,用ρ表示线段OM的长度(有时也用r表示),θ表示从Ox到OM的角度,ρ叫做点M的极径,θ叫做点M的极角,有序数对 (ρ,θ)就叫点M的极坐标。
那么给定平面上的一些点,把它们按照一个选定的中心点排成顺(逆)时针。

题意:
一只蚂蚁去吃菜,只能向左转弯,并且走过的路径会被标记,不能再走,问能吃到最多的卷心菜,输出吃菜顺序

思路:
这只蚂蚁可以像卷心菜那样一圈一圈的走,最后一定可以吃完n个卷心菜,接下来考虑先吃哪个点,肯定是先吃左下角的点,然后每次都选择拐角最小的点,就是每次以当前点为起点,对剩下的点进行极角坐标的排序;极角排序最简单的方法就是使用叉积

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const double EPS=1e-8;
int sgn(double x)
{
    if(fabs(x)<EPS) return 0;
    if(x<0) return -1;
    else    return 1;
}
 
struct Point{
    double x,y;
    int index;
    Point(){}
    Point(int _x,int _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;
    }
    //点积
    double operator *(const Point &b)const{
        return x*b.x+y*b.y;
    }
};
double dist(Point a,Point b)
{
    return sqrt((a-b)*(a-b));
}
int pos;
Point p[100];
bool cmp(Point a,Point b)
{
    double tmp=(a-p[pos])^(b-p[pos]);
    if(sgn(tmp)==0)
        return dist(p[pos],a)<dist(p[pos],b);
    else if(sgn(tmp)<0) return false;
    else    return true;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++){
            scanf("%d%lf%lf",&p[i].index,&p[i].x,&p[i].y);
            if(p[0].y>p[i].y||p[0].y==p[i].y&&p[0].x>p[i].x)
                swap(p[0],p[i]);
        }
        pos=0;
        for(int i=1;i<n;i++){
            sort(p+i,p+n,cmp);
            pos++;
        }
        printf("%d",n);
        for(int i=0;i<n;i++)
            printf(" %d",p[i].index);
        printf("\n");
    }
    return 0;
}

3、【判断线段相交】、【判断两点在线段两侧】、【判断三点共线】、【判断点在线段上】模板 POJ3449

题意:

给定一些图形及其坐标(可能是正方形、矩形、三角形、多边形、线段),问每一个图形和其他哪些图形相交

思路:

因为数据量很小,暴力判断每一个图形的每一条边和其他每一个图形的每一条边是否相交

输入输出有点恶心 没别的了

//#include 
#include<iostream>
#include<cmath>
#include<algorithm>
#include<stdio.h>
#include<cstring>

using namespace std;
typedef long long int LL;

#define zero(x) (((x) > 0? (x) : -(x)) < eps)
//enum shape{"square", "rectangle", "line", "triangle", "polygon"};
const double eps = 1e-8;
const double pi = 3.141592654;
struct point{
    int x,y;
    point()
    {
        x = 0;
        y = 0;
    }
    point(int _x, int _y)
    {
        x = _x;
        y = _y;
    }
};

struct node{
    int sh;
    int nvertices;
    point p[25];
    char name;
    /*bool operator < (const node &b)const
    {
        name < b.name;
    }*/
};
node shapes[30];

bool cmp(node a, node b)
{
    return a.name < b.name;
}

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 dots_inline(point p1, point p2, point p3)
{
    return zero(xmult(p1, p2, p3));
}

//判断点是否在线段上,包括端点
int dot_online_in(point p, point l1, point l2)
{
    return zero(xmult(p, l1, l2)) && (l1.x - p.x) * (l2.x - p.x) < eps && (l1.y - p.y) * (l2.y - p.y) < eps;
}

//判断两点在线段同侧,点在线段上返回0
int same_side(point p1, point p2, point l1, point l2)
{
    return xmult(l1, p1, l2) * xmult(l1, p2, l2) > eps;
}

//判断两线段相交,包括端点和部分重合
int intersect_in(point u1, point u2, point v1, point v2)
{
    if(!dots_inline(u1, u2, v1) || !dots_inline(u1, u2, v2)){
        return !same_side(u1, u2, v1, v2) && !same_side(v1, v2, u1, u2);
    }

    return dot_online_in(u1, v1, v2) || dot_online_in(u2, v1, v2) || dot_online_in(v1, u1, u2) || dot_online_in(v2, u1, u2);

}

/*bool inter(point u1, point u2, point v1, point v2)
{
    return
    max(u1.x, u2.x) >= min(v1.x, v2.x) &&
    max(v1.x, v2.x) >= min(u1.x, u2.x) &&
    max(u1.y, u2.y) >= min(v1.y, v2.y) &&
    max(v1.y, v2.y) >= min(u1.y, u2.y) &&
    sgn((v))
}*/

char str[30];
bool inter[30];
int main()
{
    int cnt = 0;
    while(scanf("%s", str) == 1){
        cnt = 0;
        if(str[0] =='.')break;
        shapes[0].name = str[0];
        scanf("%s", str);
        if(strcmp(str, "square") == 0){
            shapes[0].nvertices = 4;
            int x0, x2, y0, y2;
            //cin>>x0>>y0>>x2>>y2;
            scanf(" (%d,%d)", &x0, &y0);
            scanf(" (%d,%d)", &x2, &y2);
            shapes[0].p[0] = point(x0, y0);
            shapes[0].p[2] = point(x2, y2);
            shapes[0].p[1] = point((x0 + x2 + y2 - y0) / 2, (y0 + y2 + x0 - x2) / 2);
            shapes[0].p[3] = point((x0 + x2 - y2 + y0) / 2, (y0 + y2 - x0 + x2) / 2);
        }
        else if(strcmp(str, "line") == 0){
            shapes[0].nvertices = 2;
            int x0, y0, x1, y1;
            scanf(" (%d,%d) (%d,%d)", &x0, &y0, &x1, &y1);
            shapes[0].p[0] = point(x0, y0);
            shapes[0].p[1] = point(x1, y1);
        }
        else if(strcmp(str, "triangle") == 0){
            shapes[0].nvertices = 3;
            int x0, y0, x1, y1, x2, y2;
            scanf(" (%d,%d) (%d,%d) (%d,%d)", &x0, &y0, &x1, &y1, &x2, &y2);
            shapes[0].p[0] = point(x0, y0);
            shapes[0].p[1] = point(x1, y1);
            shapes[0].p[2] = point(x2, y2);
        }
        else if(strcmp(str, "rectangle") == 0){
            shapes[0].nvertices = 4;
            int x0, y0, x1, y1, x2, y2;
            scanf(" (%d,%d) (%d,%d) (%d,%d)", &x0, &y0, &x1, &y1, &x2, &y2);
            shapes[0].p[0] = point(x0, y0);
            shapes[0].p[1] = point(x1, y1);
            shapes[0].p[2] = point(x2, y2);
            shapes[0].p[3] = point(x2 + x0 - x1, y2 + y0 - y1);
        }
        else if(strcmp(str, "polygon") == 0){
            scanf("%d", &shapes[0].nvertices);
            for(int i = 0; i < shapes[0].nvertices; i++){
                scanf(" (%d,%d)", &shapes[0].p[i].x, &shapes[0].p[i].y);
            }
        }
        cnt++;
        while(scanf("%s", str) == 1){
            if(str[0] == '-')break;
            shapes[cnt].name = str[0];
            scanf("%s", str);
            if(strcmp(str, "square") == 0){
                shapes[cnt].nvertices = 4;
                int x0, x2, y0, y2;
                scanf(" (%d,%d) (%d,%d)", &x0, &y0, &x2, &y2);
                shapes[cnt].p[0] = point(x0, y0);
                shapes[cnt].p[2] = point(x2, y2);
                shapes[cnt].p[1] = point((x0 + x2 + y2 - y0) / 2, (y0 + y2 + x0 - x2) / 2);
                shapes[cnt].p[3] = point((x0 + x2 - y2 + y0) / 2, (y0 + y2 - x0 + x2) / 2);
            }
            else if(strcmp(str, "line") == 0){
                shapes[cnt].nvertices = 2;
                int x0, y0, x1, y1;
                scanf(" (%d,%d) (%d,%d)", &x0, &y0, &x1, &y1);
                shapes[cnt].p[0] = point(x0, y0);
                shapes[cnt].p[1] = point(x1, y1);
            }
            else if(strcmp(str, "triangle") == 0){
                shapes[cnt].nvertices = 3;
                int x0, y0, x1, y1, x2, y2;
                scanf(" (%d,%d) (%d,%d) (%d,%d)", &x0, &y0, &x1, &y1, &x2, &y2);
                shapes[cnt].p[0] = point(x0, y0);
                shapes[cnt].p[1] = point(x1, y1);
                shapes[cnt].p[2] = point(x2, y2);
            }
            else if(strcmp(str, "rectangle") == 0){
                shapes[cnt].nvertices = 4;
                int x0, y0, x1, y1, x2, y2;
                scanf(" (%d,%d) (%d,%d) (%d,%d)", &x0, &y0, &x1, &y1, &x2, &y2);
                shapes[cnt].p[0] = point(x0, y0);
                shapes[cnt].p[1] = point(x1, y1);
                shapes[cnt].p[2] = point(x2, y2);
                shapes[cnt].p[3] = point(x2 + x0 - x1, y2 + y0 - y1);
            }
            else if(strcmp(str, "polygon") == 0){
                scanf("%d", &shapes[cnt].nvertices);
                for(int i = 0; i < shapes[cnt].nvertices; i++){
                    scanf(" (%d,%d)", &shapes[cnt].p[i].x, &shapes[cnt].p[i].y);
                }
            }
            cnt++;
        }

        sort(shapes, shapes + cnt, cmp);
        for(int i = 0; i < cnt; i++){
            printf("%c ", shapes[i].name);
            memset(inter, 0, sizeof(inter));
            int ans = 0;
            for(int j = 0; j < cnt; j++){
                if(i == j)continue;
                for(int a = 0; a < shapes[i].nvertices; a++){
                    for(int b = 0; b < shapes[j].nvertices; b++){
                        if(intersect_in(shapes[i].p[a], shapes[i].p[(a + 1) % shapes[i].nvertices], shapes[j].p[b], shapes[j].p[(b + 1) % shapes[j].nvertices])){
                            inter[j] = true;
                        }
                    }
                }
                if(inter[j] == true){
                    ans++;
                }
            }
            if(ans == 0){
                printf("has no intersections\n");
            }
            else{
                printf("intersects with");
                if(ans == 1){
                    for(int j = 0; j < cnt; j++){
                        if(inter[j]){
                            printf(" %c\n", shapes[j].name);
                        }
                    }
                }
                else if(ans == 2){
                    int tmp = 0;
                    for(int j = 0; j < cnt; j++){
                        if(inter[j]){
                            if(tmp){
                                printf(" and");
                            }
                            printf(" %c", shapes[j].name);
                            tmp++;
                        }
                    }
                    printf("\n");
                }
                else{
                    int tmp = 0;
                    for(int j = 0; j < cnt; j++){
                        if(inter[j]){
                            if(tmp == ans - 1){
                                printf(" and %c", shapes[j].name);
                            }
                            else{
                                printf(" %c,", shapes[j].name);
                            }
                            tmp++;
                        }

                    }
                    printf("\n");
                }
            }
        }
        printf("\n");
    }
    return 0;
}

4、判断圆是否在凸包内 POJ1584

///题意:输入n个点,圆的半径以及圆的坐标X,Y。
///先是判断输入的点是不是能够组成凸包(这里的判断就是所有的点是不是往同一个方向"拐")
///然后判断圆心是否在凸包内.如果在的话就判断圆心的和凸包每条边的就离是否小于R。
#include <iostream>
#include <cstdio>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;
const int N = 1000;
const double eps = 1e-8;
struct Point
{
    double x,y;
} p[N];
Point c; ///圆心
double r; ///圆的半径
int n;
/**计算叉积*/
double cross(Point a,Point b,Point c)
{
    return (a.x-c.x)*(b.y-c.y)-(a.y-c.y)*(b.x-c.x);
}
/**判断叉积正负*/
int isCross(double k)
{
    if(k<0) return 1;
    return 0;
}
/**是否为凸包*/
bool isConvex(int n)
{
    p[n++]=p[0];
    p[n++]=p[1];
    int dir = isCross(cross(p[1],p[2],p[0]));
    for(int i=3; i<n; i++)
    {
        if(isCross(cross(p[i-1],p[i],p[i-2]))!=dir)
        {
            return false;
        }
    }
    return true;
}
/**判断点是否在多边形内(具有普遍性,不过并不能看懂)*/
bool pointInPolygon(int n,double x,double y)
{
    int   i,j=n-1;
    bool  oddNodes=0;
    for (i=0; i<n; i++)
    {
        if((p[i].y< y && p[j].y>=y|| p[j].y<y && p[i].y>=y) && (p[i].x<=x||p[j].x<=x))
        {
            oddNodes^=(p[i].x+(y-p[i].y)/(p[j].y-p[i].y)*(p[j].x-p[i].x)<x);
        }
        j=i;
    }
    return oddNodes;
}
/**判断点是否在凸多边形内(这个比较容易打并且适合这题)*/
bool pointInConvex(int n,double x,double y){
    Point po;
    p[n] = p[0];
    po.x = x,po.y = y;
    bool flag = isCross(cross(p[0],p[1],po)); ///既然是判断了是凸多边形肯定相邻两个点是朝同一个方向转
    for(int i=1;i<n;i++){
        if(isCross(cross(p[i],p[i+1],po))!=flag){
            return false;
        }
    }
    return true;
}
///点积
double mult(Point a,Point b,Point c){
    return (a.x-c.x)*(b.x-c.x)+(a.y-c.y)*(b.y-c.y);
}
///距离
double dis(Point a,Point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
///点c到线段ab的最短距离
double GetDist(Point a,Point b,Point c){
    if(dis(a,b)<eps) return dis(b,c); ///a,b是同一个点
    if(mult(b,c,a)<-eps) return dis(a,c); ///投影
    if(mult(a,c,b)<-eps) return dis(b,c);
    return fabs(cross(b,c,a)/dis(a,b));

}
/**判断圆是否在凸多边形内*/
bool circleInConvex(int n,double x,double y,double r){
    Point po;
    po.x = x,po.y = y;
    p[n]=p[0];
    for(int i=0;i<n;i++){
        if(r>GetDist(p[i],p[i+1],po)){
            return false;
        }
    }
    return true;
}
int main()
{
    while(scanf("%d",&n)!=EOF&&n>=3)
    {
        scanf("%lf%lf%lf",&r,&c.x,&c.y);
        for(int i=0; i<n; i++)
        {
            scanf("%lf%lf",&p[i].x,&p[i].y);
        }
        if(!isConvex(n)) printf("HOLE IS ILL-FORMED\n");
        else if(!circleInConvex(n,c.x,c.y,r)||!pointInConvex(n,c.x,c.y)){
            printf("PEG WILL NOT FIT\n");
        }else printf("PEG WILL FIT\n");

    }
    return 0;
}

你可能感兴趣的:(计算几何)