UVA 248 Cutting Corners 计算几何入门题+乱搞+麻烦

本文详细解析了一道UVA竞赛编程题目,通过构建矩形模型并加入对角线来准确表示建筑物,避免路径横穿建筑但不与边界相交的情况。文章介绍了如何使用叉乘求面积来快速判断点是否位于矩形内,并通过特殊判定处理建筑边缘路径。
摘要由CSDN通过智能技术生成

对于UVA已经无力吐槽了,多打了一个回车就被WA了很久。。。什么鬼玩意。。。给个PE会死嘛?!!!!!!

View Code
//Result:248     Cutting Corners     Accepted     C++     0.468     2012-07-20 07:07:55
/*
 * 1.构建矩形,因为给出了三个点,所以矩形是完全确定的。
 *      我们就要找到三个点当中的最中间的那个点。从而构建出一个有序的边序列(顺时针、逆时针均可),用来表示我们的建筑物。
 *   又因为建筑是不可横穿的,所以我们加上对角线,每个建筑存六条边。
 *   这样就不存在一条横穿建筑但是不与建筑物的任意一条边相交的路径了。
 *   如果只存四边的话,对于过对角线的特殊情况是判定无力的。
 *   这样的“六边”矩形我们管它叫“包子”。:-)
 * 
 * 2.删点,对于在建筑物里的点,因为不可能到达,所以标记删除。因为是矩形,所以可以用叉乘求面积的方法,目测比较快。
 * 3.建图,穷举每一条可能的路径,验证这条路径不可能与任一一个建筑相交。对于过建筑外沿的边,我们要加以特殊判定。
 * 4.SPFA,这个没的说了。
 */

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <bitset>
#include <queue>

using namespace std;

#define print(x) cout<<x<<endl
#define input(x) cin>>x
#define SIZE 128

const double eps=1e-8;
const double inf=1e10;

inline int zero(double x)
{
    if(x>eps) return 1;
    else if(x<-eps) return -1;
    else return 0;
}

inline double mul(double x)
{
    return x*x;
}

struct point
{
    double x,y;
    point(){}
    point(double ix,double iy)
    {
        x=ix;y=iy;
    }
};

inline double pointDis(const point& a,const point& b)
{
    return sqrt(mul(a.x-b.x)+mul(a.y-b.y));
}

inline double xmult(point sp,point ep,point op)
{
    return ((sp.x-op.x)*(ep.y-op.y)-(sp.y-op.y)*(ep.x-op.x));
}

inline double dotmult(point sp,point ep,point op)
{
    return (sp.x-op.x)*(ep.x-op.x)+(sp.y-op.y)*(ep.y-op.y);
}

struct segment
{
    point p1,p2;
    segment(){}
    segment(const point &ip1,const point &ip2)
    {
        p1=ip1;p2=ip2;
    }
};

bool segIntersect(segment l1,segment l2,point &p)//线段相交,包括特殊的情况
{
    if((max(l1.p1.x,l1.p2.x)>=min(l2.p1.x,l2.p2.x))&&
       (max(l1.p1.y,l1.p2.y)>=min(l2.p1.y,l2.p2.y))&&
       (max(l2.p1.x,l2.p2.x)>=min(l1.p1.x,l1.p2.x))&&
       (max(l2.p1.y,l2.p2.y)>=min(l1.p1.y,l1.p2.y))&&//快速排斥实验
       (xmult(l1.p1,l2.p1,l2.p2)*xmult(l1.p2,l2.p1,l2.p2)<=eps)&&
       (xmult(l2.p1,l1.p1,l1.p2)*xmult(l2.p2,l1.p1,l1.p2)<=eps))//跨立实验
    {
        //lineIntersect(makeLine(l1),makeLine(l2),p);
        return true;
    }
    else return false;
}

bool onSegment(segment s,point p)
{
    return fabs(xmult(s.p2,p,s.p1))<eps && (p.x-s.p1.x)*(p.x-s.p2.x)<=0 && (p.y-s.p1.y)*(p.y-s.p2.y)<=0;
}

struct rect
{
    point p[4];
    segment s[6];
    double area;

    rect(){}
    rect(const point *ip)
    {
        this->setRect(ip);
    }
    void setRect(const point *ip)
    {
        for(int i=0;i<3;i++)
        {
            p[i]=ip[i];
        }
        int ptr=-1;
        for(int i=0;i<3;i++)
        {
            if(zero(dotmult(p[(i+1)%3],p[(i+2)%3],p[i]))==0)
            {
                ptr=i;
                break;
            }
        }

        if(ptr==-1) print("Not a Rect");
        else
        {
            swap(p[0],p[ptr]);
            area=fabs(xmult(p[1],p[2],p[0]));
            double dx=p[0].x-p[1].x;
            double dy=p[0].y-p[1].y;
            p[3]=point(p[2].x-dx,p[2].y-dy);
            swap(p[2],p[3]);
        }
        for(int i=0;i<4;i++)
        {
            s[i]=segment(p[i],p[(i+1)%4]);
        }
        s[4]=segment(p[0],p[2]);
        s[5]=segment(p[1],p[3]);
    }
    
    bool inrect(const point& ip)
    {
        double res=0;
        for(int i=0;i<4;i++)
        {
            int j=(i+1)%4;
            res+=fabs(xmult(p[i],p[j],ip))/2;
        }
        bool flag=true;
        for(int i=0;i<4;i++)
        {
            if(onSegment(s[i],ip))
            {
                flag=false;
                break;
            }
        }
        return zero(res-area)==0 && flag;
    }
};

point start,end;
int n,sz;
rect house[SIZE];
int ind;
vector< pair<int,double> > g[SIZE];

void makeG()
{
    for(int i=0;i<SIZE;i++) g[i].clear();
    vector< pair<point,int> > pvec;
    pvec.push_back(make_pair(start,1));
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<4;j++)
        {
            pvec.push_back(make_pair(house[i].p[j],1));
        }
    }
    pvec.push_back(make_pair(end,1));
    sz=pvec.size();
    for(int i=0;i<sz;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(house[j].inrect(pvec[i].first))
            {
                pvec[i].second=0;
                break;
            }
        }
    }
    
    for(int i=0;i<sz;i++)
    {
        if(!pvec[i].second) continue;
        for(int j=i+1;j<sz;j++)
        {
            if(!pvec[j].second) continue;
            
            segment edge(pvec[i].first,pvec[j].first);
            bool cross=false;
            for(int k=0;k<n && !cross;k++)
            {
                for(int l=0;l<6;l++)
                {
                    if(onSegment(house[k].s[l],edge.p1) ||
                        onSegment(house[k].s[l],edge.p2) ||
                        onSegment(edge,house[k].s[l].p1) ||
                        onSegment(edge,house[k].s[l].p2))
                    {
                        continue;
                    }
                    else
                    {
                        point c;
                        if(segIntersect(edge,house[k].s[l],c))
                        {
                            cross=true;
                            break;
                        }
                    }
                }
            }
            if(!cross)
            {
                double dis=pointDis(pvec[i].first,pvec[j].first);
                g[i].push_back(make_pair(j,dis));
                g[j].push_back(make_pair(i,dis));
            }
        }
    }
}

double spfa(int st,int end)
{
    double dis[SIZE<<2];
    fill(dis,dis+(SIZE<<2),inf);
    queue<int> q;
    q.push(st);
    bitset< (SIZE<<2) > visit;
    dis[st]=0;
    while(!q.empty())
    {
        int now=q.front();
        q.pop();
        visit[now]=0;
        
        for(int i=0;i<(int)g[now].size();i++)
        {
            int next=g[now][i].first;
            double dist=g[now][i].second;
            
            if(dis[now]+dist<dis[next])
            {
                dis[next]=dis[now]+dist;
                if(!visit[next])
                {
                    visit[next]=1;
                    q.push(next);
                }
            }
        }
    }
    return dis[end];
}

int main()
{
    double a,b,c,d;
    int cas=1;
    while(input(n) && n>=0)
    {
        scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
        start=point(a,b);
        end=point(c,d);
        point array[3];
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<3;j++)
            {
                scanf("%lf%lf",&a,&b);
                array[j]=point(a,b);
            }
            house[i]=rect(array);
        }
        makeG();
        
        if(cas>1) puts("");
        printf("Scenario #%d\n",cas++);
        printf("   route distance: %.2f\n",spfa(0,sz-1));
    }
    return 0;
}

 

 

转载于:https://www.cnblogs.com/Wizmann/archive/2012/07/20/2601263.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值