Liaoning Ship’s Voyage(计算几何:点在三角形内的判定+线段穿过三角形的判定)

Liaoning Ship’s Voyage

题意:在一个(n*n)的区域内,"."可以走,"#"不可以走,同时给定三个点,这三个点围成的三角形区域也是不可以走的。船的起始位置在(0,0)处(左下角),终点在(n-1,n-1)(右上角),问小船从起始位置到终点所要花费的最小时间。

题解:对每个点标号,建图,用(bfs)跑出最短路。连边时要判断路线是否穿过三角形,具体方法是,在路线上平均取1000个点,若1000个点都不在三角形中,则认为该路线没有穿过三角形。

AC_Code:(注意代码中num数组的num[i][j]不对应坐标系中的(i,j)点,对应的是(j,i)点,注意体会一下)

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 typedef long long ll;
  4 #define endl '
'
  5 const ll inf = 0x3f3f3f3f3f3f3f3f;
  6 const int maxn = 110;
  7 const double eps = 1e-7;
  8 
  9 
 10 struct Point{
 11     double x,y;
 12     Point(double x=0, double y=0):x(x),y(y){}
 13 };
 14 
 15 typedef Point Vector;
 16 Vector operator+(Vector A, Vector B) { return Vector(A.x+B.x,A.y+B.y); }
 17 Vector operator-(Vector A, Vector B) { return Vector(A.x-B.x,A.y-B.y); }
 18 Vector operator*(Vector A, double B) { return Vector(A.x*B,A.y*B); }
 19 Vector operator/(Vector A, double B) { return Vector(A.x/B,A.y/B); }
 20 
 21 int sgn(double x){
 22     if( fabs(x)<eps ) return 0;
 23     else if( x<0 ) return -1;
 24     else return 1;
 25 }
 26 
 27 bool operator <(const Point &a, const Point &b){
 28     if( a.x==b.x ) return a.y<b.y;
 29     return a.x<b.x;
 30 }
 31 bool operator == (const Point &a,const Point &b){
 32     if( sgn(a.x-b.x)==0 && sgn(a.y-b.y)==0 ) return true;
 33     return false;
 34 }
 35 
 36 double Dot(Vector A, Vector B) { return A.x*B.x+A.y*B.y; }
 37 double Length(Vector A) { return sqrt(Dot(A,A));}
 38 double Cross(Vector A, Vector B) { return A.x*B.y-A.y*B.x; }
 39 
 40 int n,en;
 41 int num[22][22];
 42 char x[22];
 43 int dirx[8] = {0,1,1,1,0,-1,-1,-1};
 44 int diry[8] = {1,1,0,-1,-1,-1,0,1};
 45 vector<int>G[410];
 46 Point a[4];
 47 int _time[410],f[410];
 48 
 49 bool isPointInPolygon(Point p){//点在三角形内的判定
 50     return sgn(Cross(a[1]-a[0],p-a[0]))>0 && sgn(Cross(a[2]-a[1],p-a[1]))>0 && sgn(Cross(a[0]-a[2],p-a[2]))>0;
 51 }
 52 
 53 bool check(Point x,Point y){//两点之间连边时判断是否穿过三角形,具体方法:在路线上平均取1000个点,若1000个点都不在三角形内,则认为该路线没有穿过三角形
 54     for(int i=1;i<=1000;i++){
 55         Point t=x+(y-x)/1000.0*(double)i;
 56         if( isPointInPolygon(t)==1 ) return false;
 57     }
 58     return true;
 59 }
 60 
 61 int bfs(int n){
 62     queue<int>q;
 63     for(int i=1;i<=n;i++) _time[i]=1000000;
 64     while( !q.empty() ) q.pop();
 65     q.push(1);
 66     f[1]=true;
 67     _time[1]=0;
 68 
 69     while( !q.empty() ){
 70         int x=q.front(); q.pop();
 71         for(int i=0; i<G[x].size(); i++){
 72             int v=G[x][i];
 73             if( _time[x]+1<_time[v] ){
 74                 _time[v]=_time[x]+1;
 75                 if( !f[v] ){
 76                     q.push(v);
 77                     f[v]=true;
 78                 }
 79             }
 80         }
 81     }
 82     if( _time[en]==1000000 ) return -1;
 83     else return _time[en];
 84 }
 85 
 86 
 87 int main()
 88 {
 89     while( ~scanf("%d",&n)){
 90         memset(num,0,sizeof(num));
 91         memset(G,0,sizeof(G));
 92         memset(f,false,sizeof(f));
 93 
 94         for(int i=0;i<3;i++)
 95             scanf("%lf%lf",&a[i].x,&a[i].y);
 96 
 97         if( sgn(Cross(a[1]-a[0],a[2]-a[0]))<0 ) //向量02在向量01的顺时针方向
 98             swap(a[1],a[2]);//交换使得按0,1,2的顺序是逆时针
 99 
100         for(int i=n-1;i>=0;i--){
101             scanf("%s",x);
102             for(int j=0;j<n;j++){
103                 if( x[j]=='#' || isPointInPolygon(Point(j,i))==1 )
104                     num[i][j]=-1;
105             }
106         }
107         int t=0;
108         for(int i=0;i<n;i++){
109             for(int j=0;j<n;j++){
110                 if( num[i][j]!=-1 )
111                     num[i][j]=++t;
112             }
113         }
114 
115         for(int i=0;i<n;i++){
116             for(int j=0;j<n;j++){
117                 if( num[i][j]!=-1 ){
118                     for(int k=0;k<8;k++){
119                         int x=i+dirx[k];
120                         int y=j+diry[k];
121                         if( !(x>=0 && x<n && y>=0 && y<n && num[x][y]!=-1) ) continue;
122                         if( check(Point(j,i),Point(y,x))){
123                             int u=num[i][j];
124                             int v=num[x][y];
125                             G[u].push_back(v);
126                         }
127                     }
128                 }
129             }
130         }
131 
132         en = num[n-1][n-1];
133         if( en==-1 ) printf("-1
");
134         else printf("%d
",bfs(en));
135     }
136     return 0;
137 }

大佬博客:here

原文地址:https://www.cnblogs.com/wsy107316/p/13550173.html