ICPC 2017 北京 Liaoning Ship’s Voyage

题目地址:http://hihocoder.com/problemset/problem/1633?sid=1234017

 

题目大意:在二维平面内,船从(0,0)出发到(n-1,n-1)结束,求最短路,要求:一个点可以向周围8个方向走,距离都为1,并告诉哪些点不可以走,同时要求路线不可以穿过一个三角形。

 

 

 

题解:对每个点标号,建图,最后SPFA搞一下。连边时要判断路线是否穿过三角形,具体方法是,在路线上平均取100个点,若100个点都不在三角形中,则认为该路线没有穿过三角形。

 

 

 

 

#include<bits/stdc++.h>
#define LL long long
const double eps=1e-7;
using namespace std;
int dcmp(double x){if (fabs(x)<eps)return 0;else return x<0?-1:1;}
struct Point
{
    double x,y;
    bool operator < (const Point &a)const
    {return dcmp(x-a.x)<0 || (dcmp(x-a.x)==0 && dcmp(y-a.y)<0);}
    Point(double x=0,double y=0):x(x),y(y){ }

};
typedef Point Vector;
Vector operator + (Vector a,Vector b){return Vector(a.x+b.x,a.y+b.y);}
Vector operator - (Vector a,Vector b){return Vector(a.x-b.x,a.y-b.y);}
Vector operator * (Vector a,double b){return Vector(a.x*b,a.y*b);}
Vector operator / (Vector a,double b){return Vector(a.x/b,a.y/b);}
bool operator == (Vector a,Vector b){return a.x==b.x && a.y==b.y;}
double Dot(Vector a,Vector b){return a.x*b.x+a.y*b.y;}  //点积
double Length(Vector a){return sqrt(Dot(a,a));}
double Cross(Vector a,Vector b){return a.x*b.y-a.y*b.x;} //叉积

int i,j,k,l,n,m,t,h,en,d[410];
Point a[4];
int num[22][22];
char x[22];
int dx[8]={0,1,1,1,0,-1,-1,-1},dy[8]={1,1,0,-1,-1,-1,0,1};      //8个方向向量
vector<int> G[410];


bool isPointInPolygon(Point p)         //点在三角形内判定
{
    return dcmp(Cross(a[1]-a[0],p-a[0]))>0 && dcmp(Cross(a[2]-a[1],p-a[1]))>0 && dcmp(Cross(a[0]-a[2],p-a[2]))>0;
}

bool check(Point x,Point y)            //检查路线x->y是否穿过三角形
{
    for (int i=1;i<=1000;i++)
    {
        Point t=x+(y-x)/1000.0*(double)i;
        if (isPointInPolygon(t)==1) return false;
    }
    return true;
}

int  SPFA(int n)                        //求最短路
{
    int i,j,k,l;
    bool f[410]={0};
    queue<int>q;
    while (!q.empty())q.pop();
    for (i=2;i<=n;i++) d[i]=1000000;
    q.push(1);f[1]=1;d[1]=0;
    while (!q.empty())
    {
        int x=q.front();q.pop();
        for (int i=0;i<G[x].size();i++)
        {
            int v=G[x][i];
            if (d[x]+1<d[v])
            {
                d[v]=d[x]+1;
                if (!f[v])
                {
                    q.push(v);
                    f[v]=1;
                }
            }
        }
        f[x]=0;
    }
    if (d[en]==1000000)return -1;else return d[en];
}

int main()
{
    while (~scanf("%d",&n))
    {
        memset(num,0,sizeof num);memset(G,0,sizeof G);
        for (i=0;i<3;i++) scanf("%lf%lf",&a[i].x,&a[i].y);
        if (dcmp(Cross(a[1]-a[0],a[2]-a[0]))<0) swap(a[1],a[2]);

        for (i=n-1;i>=0;i--)
        {
            scanf("%s",x);
            for (j=0;j<n;j++)if (x[j]=='#' || isPointInPolygon(Point(j,i))==1) num[i][j]=-1;
        }

        t=0;
        for (i=0;i<n;i++)for (j=0;j<n;j++) if (num[i][j]!=-1)num[i][j]=++t;     //标号
        
        for (i=0;i<n;i++)
            for (j=0;j<n;j++) if (num[i][j]!=-1)                                //建图
        {
            for (k=0;k<8;k++)
            {
                int x=i+dx[k],y=j+dy[k];
                if (!(x>=0 && x<n && y>=0 && y<n && num[x][y]!=-1))continue;
                if (check(Point(j,i),Point(y,x)))
                {
                    int u=num[i][j],v=num[x][y];
                    G[u].push_back(v);
                }
            }
        }
        
        en=num[n-1][n-1];
        if (en==-1)printf("-1\n");else printf("%d\n",SPFA(en));
    }
    return 0;
}

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值