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 '\n' 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\n"); 134 else printf("%d\n",bfs(en)); 135 } 136 return 0; 137 }
大佬博客:here