[kuangbin专题十三 ]基础计算几何 —[部分题解1]

AC is lucky , WA is life.

问题虫洞——A: A - TOYS

问题虫洞——B: B - Toy Storage

两题个大致思想相同,参考我的另一篇博客吧!:TOYS POJ - 2318 (二分+斜率)

 

问题虫洞——C: C - Segments

 

黑洞内窥:

t组样例,每组样例给出n条线段的两个端点坐标

问是否存在这样一条直线,所以线段在该线段上的投影有公共点。

 

思维光年:

问题可以转换为:是否存在一条直线,使得该直线与所有的线段相交。

然后你枚举所有线段的端点连线,判断是否与所有线段相交即可:

 

ACcode:

//#include<bits/stdc++.h>
#include  <stdio.h>
#include <iostream>
#include<algorithm>
#include      <map>
#include      <set>
#include   <vector>
#include    <queue>
#include    <stack>
#include <stdlib.h>
#include  <cstring>
#include <string.h>
#include   <string>
#include   <math.h>
#include  <sstream>
using namespace std;
typedef long long int ll;
const ll MAXN = 1005;
#define INF 0x3f3f3f3f//将近ll类型最大数的一半,而且乘2不会爆ll
const ll mod = 100000007;
const double eps = 0.00000001;

struct node
{
    double x1, y1, x2, y2;
} stu[MAXN];
int n, t;

double go(double x1, double y1, double x2, double y2)
{
    return sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
}

double cha(double x1,double y1,double x2,double y2,double x,double y)
{
    return (x2-x1)*(y-y1)-(x-x1)*(y2-y1);
}

int so(double x1, double y1, double x2, double y2)
{
    if(go(x1, y1, x2, y2) < eps) return 0;//可能点重合
    for(int i=0; i<n; ++i)
    {
        if(cha(x1, y1, x2, y2, stu[i].x1, stu[i].y1) * cha(x1, y1, x2, y2, stu[i].x2, stu[i].y2)>eps)
            return 0;
    }
    return 1;
}

int main()
{
    cin >> t;
    while(t--)
    {
        scanf("%d", &n);
        for(int i=0; i<n; ++i)
            scanf("%lf %lf %lf %lf", &stu[i].x1, &stu[i].y1, &stu[i].x2, &stu[i].y2);
        if(n == 1) {
            puts("Yes!");
            continue;
        }
        int flag = 0;
        for(int i=0; i<n && !flag; ++i)
        {
            for(int j= i+1; j<n && !flag; ++j)
                if(so(stu[i].x1, stu[i].y1, stu[j].x1, stu[j].y1) || so(stu[i].x1, stu[i].y1, stu[j].x2, stu[j].y2) || so(stu[i].x2, stu[i].y2, stu[j].x1, stu[j].y1) || so(stu[i].x2, stu[i].y2, stu[j].x2, stu[j].y2))
                    flag = 1;
        }
        if(flag) puts("Yes!");
        else puts("No!");
    }
    return 0;
}

 

 

 问题虫洞——D: D - Intersecting Lines

 

黑洞内窥:

n组样例,每组样例给出两条线段的坐标,即八个点坐标

问每组样例的两条线段是平行,重合还是相交

如果相交,请输出交点。

 

思维光年:

枚举两条线段的所以情况;

 

ACcode:

//#include<bits/stdc++.h>
#include  <stdio.h>
#include <iostream>
#include<algorithm>
#include      <map>
#include      <set>
//#include   <vector>
//#include    <queue>
//#include    <stack>
#include <stdlib.h>
#include  <cstring>
#include <string.h>
#include   <string>
#include   <math.h>
#include  <sstream>
using namespace std;
typedef long long int ll;
const ll MAXN = 5005;
#define INF 0x3f3f3f3f//将近ll类型最大数的一半,而且乘2不会爆ll
const ll mod = 100000007;
const double eps = 0.0000001;

int main()
{
    int t;
    cin >> t;
    puts("INTERSECTING LINES OUTPUT");
    while(t--)
    {
        double x1, y1, x2, y2, x3, y3, x4, y4;
        scanf("%lf %lf %lf %lf %lf %lf %lf %lf", &x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4);
        double a1=0, b1=0, a2=0, b2=0;
        int f1 = 0, f2 = 0;//判断线段1和2是否垂直x轴
        if(x1 == x2) f1 = 1;//垂直无斜率
        else {
            a1 = (y2 - y1)/(x2 - x1);
            b1 = y1 - a1*x1;
        }
        if(x3 == x4) f2 = 1;
        else {
            a2 = (y4 - y3)/(x4 - x3);
            b2 = y3 - a2*x3;
        }

        if(f1 && f2 && x1!=x3) puts("NONE");
        else if(f1 && f2 && x1 == x3) puts("LINE");
        else if(f1 && !f2)
        {
            double x = x1;
            double y = a2*x+b2;
            printf("POINT %.2f %.2f\n", x, y);
        }
        else if(!f1 && f2)
        {
             double x = x3;
            double y = a1*x+b1;
            printf("POINT %.2f %.2f\n", x, y);
        }
        else if(!f1 && !f2 && fabs(a1-a2) < eps && fabs(b1-b2) < eps) puts("LINE");
        else if(!f1 && !f2 && fabs(a1-a2) < eps && b1 != b2) puts("NONE");
        else {
            double x = (b2-b1)*1.0/(a1-a2);
            double y = a1*x + b1;
            printf("POINT %.2f %.2f\n", x, y);
        }
    }
    puts("END OF OUTPUT");
    return 0;
}

 

 

 问题虫洞——F: F - Pick-up sticks

 

黑洞内窥:

有n条木棍,编号为1~n,按顺序给出木棍的位置,

木棍之间相交则必有一条木棍在上面,求顶部木棍的编号。

 

思维光年:

把木棍想成线段,求n条线段相交,即线段交

 

ACcode:

//#include<bits/stdc++.h>
#include  <stdio.h>
#include <iostream>
#include<algorithm>
//#include      <map>
//#include      <set>
//#include   <vector>
//#include    <queue>
//#include    <stack>
#include <stdlib.h>
#include  <cstring>
#include <string.h>
#include   <string>
#include   <math.h>
using namespace std;
typedef long long ll;
#define MAXN 100005
#define INF 0x3f3f3f3f//将近ll类型最大数的一半,而且乘2不会爆ll

struct point
{
    double x,y;
};
struct line
{
    point p1,p2;
} a[100010];
//叉乘
double chacheng(point p1,point p2,point p3)
{
    return (p1.x-p3.x)*(p2.y-p3.y)-(p1.y-p3.y)*(p2.x-p3.x);
}
//判断是否相交
int judge(line l1,line l2)
{
    if( min(l2.p1.x,l2.p2.x)<=max(l1.p1.x,l1.p2.x)
            && min(l2.p1.y,l2.p2.y)<=max(l1.p1.y,l1.p2.y)
            && min(l1.p1.x,l1.p2.x)<=max(l2.p1.x,l2.p2.x)
            && min(l1.p1.y,l1.p2.y)<=max(l2.p1.y,l2.p2.y)
            && chacheng(l1.p1,l2.p2,l2.p1)*chacheng(l1.p2,l2.p2,l2.p1)<=0//这里需要等于,因为木棍可能堆叠起来。
            && chacheng(l2.p1,l1.p2,l1.p1)*chacheng(l2.p2,l1.p2,l1.p1)<=0 )
        return 1;
    else
        return 0;
}
bool is[MAXN];
int main()
{
    int n;
    while(cin >> n && n)
    {
        memset(is, 0, sizeof(is));
        for(int i=0; i<n; ++i)
            scanf("%lf %lf %lf %lf", &a[i].p1.x, &a[i].p1.y, &a[i].p2.x, &a[i].p2.y);
        for(int i=0; i<n-1; ++i)
            for(int j=i+1; j<n; ++j)
                if(judge(a[i], a[j]))
                {
                    is[i] = 1;
                    break;
                }
        printf("Top sticks: ");
        for(int i=0; i<n; ++i)
        {
            if(!is[i])
            {
                cout << i+1;
                if(i == n-1)
                    cout << ".\n";
                else
                    cout << ", ";
            }
        }
    }
}

 

 

 问题虫洞——G: G - Treasure Hunt

 

黑洞内窥:

一个100*100的矩阵,中间有n条线段切割,每条线段代表一扇长长的门

然后给出一个宝藏的坐标,从矩阵的外面穿过矩阵(矩阵算一层门)到宝藏,

每次只能走一段门的中点,求至少要经过多少扇门才能拿到宝藏。

 

思维光年:

中点不重要,又不是求最短路,,

我们要求的是破门的个数,直接暴力枚举矩阵的边界到宝藏这条线段与所有门的线段交。

取最小值++就绿了~~~~

 

ACcode:

//#include<bits/stdc++.h>
#include  <stdio.h>
#include <iostream>
#include<algorithm>
//#include      <map>
//#include      <set>
//#include   <vector>
//#include    <queue>
//#include    <stack>
#include <stdlib.h>
#include  <cstring>
#include <string.h>
#include   <string>
#include   <math.h>
using namespace std;
typedef long long ll;
#define MAXN 100005
#define INF 0x3f3f3f3f//将近ll类型最大数的一半,而且乘2不会爆ll

struct point
{
    double x,y;
};
struct line
{
    point p1,p2;
} a[50], cf;
double chacheng(point p1,point p2,point p3)
{
    return (p1.x-p3.x)*(p2.y-p3.y)-(p1.y-p3.y)*(p2.x-p3.x);
}
int judge(line l1,line l2)//线段ll和线段l2是否相交
{
    if(    min(l2.p1.x, l2.p2.x)<=max(l1.p1.x, l1.p2.x)
        && min(l2.p1.y, l2.p2.y)<=max(l1.p1.y, l1.p2.y)
        && min(l1.p1.x, l1.p2.x)<=max(l2.p1.x, l2.p2.x)
        && min(l1.p1.y, l1.p2.y)<=max(l2.p1.y, l2.p2.y)
        && chacheng(l1.p1, l2.p2, l2.p1)*chacheng(l1.p2, l2.p2, l2.p1)<0//这里不能相等,否则你会wa到枯的~~~~,,,因为如果门重合了,你就不可能走这扇门了。
        && chacheng(l2.p1, l1.p2, l1.p1)*chacheng(l2.p2, l1.p2, l1.p1)<0)
        return 1;
    return 0;
}

int main()
{
    int n;
    cin >> n;
    if(n == 0)
        puts("Number of doors = 1");
    else
    {
        for(int i=0; i<n; ++i)
            scanf("%lf %lf %lf %lf", &a[i].p1.x, &a[i].p1.y, &a[i].p2.x, &a[i].p2.y);
        scanf("%lf %lf", &cf.p2.x, &cf.p2.y);
        int ans = INF;
        for(int i=1; i<=100; ++i)
        {
            cf.p1.x = 0.0, cf.p1.y = i*1.0;
            int tot = 0;
            for(int j=0; j<n; ++j)
            {
                if(judge(cf, a[j]))
                    tot++;
            }
            ans = min(ans, tot);

            cf.p1.x = 100.0, cf.p1.y = i*1.0;
            tot = 0;
            for(int j=0; j<n; ++j)
            {
                if(judge(cf, a[j]))
                    tot++;
            }
            ans = min(ans, tot);

            cf.p1.x = i*1.0, cf.p1.y = 0.0;
            tot = 0;
            for(int j=0; j<n; ++j)
            {
                if(judge(cf, a[j]))
                    tot++;
            }
            ans = min(ans, tot);

            cf.p1.x = i*1.0, cf.p1.y = 100.0;
            tot = 0;
            for(int j=0; j<n; ++j)
            {
                if(judge(cf, a[j]))
                    tot++;
            }
            ans = min(ans, tot);
            if(ans == 0)
                break;
        }
        cout << "Number of doors = " << ans+1 << '\n';
    }
    return 0;
}

 

 

 问题虫洞——H: H - Intersection

 

黑洞内窥:

输入四个点,前两点确定一条线段,

后两点确定一个矩阵,让你判断矩阵和线段的关系。

若相交输出T,否则输出F

 

思维光年:

线段和矩阵相交的条件:

1、线段在矩阵内;

2、线段和矩阵的边有交点

 

ACcode:

//#include<bits/stdc++.h>
#include  <stdio.h>
#include <iostream>
#include<algorithm>
//#include      <map>
//#include      <set>
//#include   <vector>
//#include    <queue>
//#include    <stack>
#include <stdlib.h>
#include  <cstring>
#include <string.h>
#include   <string>
#include   <math.h>
using namespace std;
typedef long long ll;
#define MAXN 100005
#define INF 0x3f3f3f3f//将近ll类型最大数的一半,而且乘2不会爆ll

struct point
{
    double x,y;
};
struct line
{
    point p1,p2;
} a[5], cf;
double chacheng(point p1,point p2,point p3)
{
    return (p1.x-p3.x)*(p2.y-p3.y)-(p1.y-p3.y)*(p2.x-p3.x);
}
int judge(line l1,line l2)//线段ll和线段l2是否相交
{
    if(    min(l2.p1.x, l2.p2.x)<=max(l1.p1.x, l1.p2.x)
        && min(l2.p1.y, l2.p2.y)<=max(l1.p1.y, l1.p2.y)
        && min(l1.p1.x, l1.p2.x)<=max(l2.p1.x, l2.p2.x)
        && min(l1.p1.y, l1.p2.y)<=max(l2.p1.y, l2.p2.y)
        && chacheng(l1.p1, l2.p2, l2.p1)*chacheng(l1.p2, l2.p2, l2.p1)<=0//判断在同一点的两侧
        && chacheng(l2.p1, l1.p2, l1.p1)*chacheng(l2.p2, l1.p2, l1.p1)<=0)
        return 1;
    return 0;
}

double xx[2], yy[2];
int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        memset(a, 0, sizeof(a));
        scanf("%lf %lf %lf %lf %lf %lf %lf %lf", &cf.p1.x, &cf.p1.y, &cf.p2.x, &cf.p2.y, &xx[0], &yy[0], &xx[1], &yy[1]);
        sort(xx, xx+2); sort(yy, yy+2);//存矩阵的边
        a[0].p1.x = xx[0], a[0].p1.y = yy[0];
        a[0].p2.x = xx[1], a[0].p2.y = yy[0];
        a[1].p1.x = xx[0], a[1].p1.y = yy[0];
        a[1].p2.x = xx[0], a[1].p2.y = yy[1];

        a[2].p1.x = xx[1], a[2].p1.y = yy[1];
        a[2].p2.x = xx[1], a[2].p2.y = yy[0];
        a[3].p1.x = xx[1], a[3].p1.y = yy[1];
        a[3].p2.x = xx[0], a[3].p2.y = yy[1];
        if(xx[0]<=cf.p1.x && cf.p1.x <= xx[1] && xx[0]<=cf.p2.x && cf.p2.x <= xx[1] && yy[0]<=cf.p1.y && cf.p1.y <= yy[1] && yy[0]<=cf.p2.y && cf.p2.y <= yy[1])
            puts("T");
        else
        {
            int tot=0;
            for(int i=0; i<4; ++i)
                if(judge(cf, a[i]))
                    tot++;
            if(tot) puts("T");
            else puts("F");
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值