2017北京区域赛 G - Liaoning Ship’s Voyage【计算几何+bfs】

题目大意:一个图上有n*n个点,然后从起点走到终点,然后需要绕过三角形和“#”,问一个最短路径
分析:由于边上的点和端点都是能走的,我在扩展边的时候,判断该边与三角形是否有焦点,我原先是判断线段与线段的交点,然后判断点是否在三角形内部,后来发现如果一个线段的起点和终点都不在三角形内部的话,也是有可能穿过三角形的,所以后来我们枚举了线段上的100个点,判断是否在三角形内部

#include <bits/stdc++.h>
using namespace std;
char mp[50][50];
int dist[50][50];
const int inf=0x3f3f3f3f;
double eps=1e-8;
int n;
struct point
{
    double x,y;
    point(double X=0,double Y=0)
    {
        x=X,y=Y;
    }
};
point operator +(point a,point b)
{
    return point(a.x+b.x,a.y+b.y);
}
point operator -(point a,point b)
{
    return point(a.x-b.x,a.y-b.y);
}
point operator *(point a,double p)
{
    return point(a.x*p,a.y*p);
}
point operator /(point a,double p)
{
    return point(a.x/p,a.y/p);
}
double len(point a)
{
    return sqrt(a.x*a.x+a.y*a.y);
}
double dot(point a,point b)
{
    return a.x*b.x+a.y*b.y;
}
double cross(point a,point b)
{
    return a.x*b.y-a.y*b.x;
}
int dcmp(double x)
{
    if(fabs(x)<eps) return 0;
    else return x<0?-1:1;
}
bool operator == (point a,point b)
{
    if(dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0)return true;
    else return false;
}
bool segment(point a,point b,point c,point d)
{
    double c1 = cross(b-a,c-a);
    double c2 = cross(b-a,d-a);
    double d1 = cross(d-c,a-c);
    double d2 = cross(d-c,b-c);
    return dcmp(c1)*dcmp(c2)<0&&dcmp(d1)*dcmp(d2)<0;
}
double dists(point p,point a,point b)
{
    if(a==b) return len(p-a);
    point v1 = b-a,v2 = p-a,v3=p-b;
    if(dcmp(dot(v1,v2))<0) return len(v2);
    else if(dcmp(dot(v1,v3))>0) return len(v3);
    return fabs(cross(v1,v2))/len(v1);
}
point tri[5];
int pointin(point p,point *a,int n)
{
    int wn = 0,k,d1,d2;
    for(int i=1; i<=n; i++)
    {
        if(dcmp(dists(p,a[i],a[i%n+1]))==0) return 0;
        k = dcmp(cross(a[i%n+1]-a[i],p-a[i]));
        d1 = dcmp(a[i].y-p.y);
        d2 = dcmp(a[i%n+1].y-p.y);
        if(k>0&&d1<=0&&d2>0) wn++;
        if(k<0&&d2<=0&&d1>0) wn--;
    }
    if(wn) return 1;
    else return 0;
}
bool check(int x,int y,int fx,int fy)
{
    if(fx<0||fx>=n||fy<0||fy>=n)return false;
    if(mp[x][y]=='#'||mp[fx][fy]=='#')return false;
    point a,b,c;
    a.x=y;
    a.y=x;
    b.x=fy;
    b.y=fx;
    for(int i=1; i<=3; i++)
    {
        if(segment(a,b,tri[i],tri[i%3+1])) return false;
    }
    if(pointin(a,tri,3)) return false;
    if(pointin(b,tri,3)) return false;
    for(int i=1;i<=100;i++)
    {
        double p = i*0.01;
        c.x=a.x+(b.x-a.x)*p;
        c.y = a.y+(b.y-a.y)*p;
        if(pointin(c,tri,3)) return false;
    }
    return true;
}
int fx[8] = {0, 0, 1,-1, 1, 1,-1,-1};
int fy[8] = {1,-1, 0, 0, 1,-1, 1,-1};
int d[500];
bool bfs(int s, int t)
{
    memset(d,-1,sizeof(d));
    queue<int> q;
    q.push(s*n+t);
    d[s*n+t]=0;
    while(!q.empty())
    {
        int u  = q.front();
        q.pop();
        int x = u/n;
        int y = u%n;
        if(u == n*n-1)  return true;
        for(int i = 0; i < 8; i++)
        {
            int fx1 = x + fx[i];
            int fy1 = y + fy[i];
            if(check(x,y,fx1,fy1) && d[fx1*n+fy1] == -1)
            {
                d[fx1*n+fy1] = d[u] + 1;
                q.push(fx1*n+fy1);
            }
        }
    }
    return false;
}


int main()
{

    while(~scanf("%d",&n))
    {
        for(int i=1; i<=3; i++)
        {
            scanf("%lf%lf",&tri[i].x,&tri[i].y);
        }
        /*point st=point(1.5,1);
        cout<<pointin(st,tri,3)<<endl;*/
        for(int i=n-1; i>=0; i--)
        {
            scanf("%s",mp[i]);
        }
        if(bfs(0,0))
        {
            printf("%d\n",d[n*n-1]);
        }
        else printf("-1\n");
    }
    return 0;
}
/*
4
1 1 2 2 0 2
#...
#.##
#.##
..##


*/
全部评论

相关推荐

点赞 评论 收藏
分享
一个非常好用的遍历方法
AomaYple:不是指针,是引用
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务