题目地址: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;
}