「2017ACM/ICPC亞洲區域賽北京站現場賽G」Liaoning Ship's Voyage【計算幾何】

Liaoning Ship’s Voyage

Liaoning shipLiaoning\ ship, which named after a province of China, is the first aircraft carrier commissioned into the Peoples Liberation Army Navy.People's\ Liberation\ Army\ Navy. It was bought from UkraineUkraine as a stripped hulk and was rebuilt by China as an important part of China’s blue water Navy plan. Liaoning ship has sailed far into the Pacific Ocean for serval times, which shows the power and resolve of China to defend her integrity of territory.

Now Liaoning shipLiaoning\ ship is on a new voyage to the Atlantic Ocean for a maneuver! The vast maneuver region on the ocean can be seen as an n×nn\times n grid which has n×nn\times n crosspoints. Each crosspoint stands for a check point of the maneuver region. Liaoning starts from the bottom-left check point whose coordinate is (0,0)(0,0), and its destination is the upper-right checkpoint whose coordinate is (n1,n1).(n-1,n-1). The positive side of the xx axis points to the right, and the positive side of the y axis points up. All check points’ coordinates are integral. During each move, LiaoningLiaoning can go from one check point to its adjacent 88 check points along a straight line, and each move takes LiaoningLiaoning one day. Some check points are not available to go due to the bad weather. And, as you know, on the Atlantic Ocean, there is a Bermuda Triangle in which many ships and planes were missing. LiaoningLiaoning can’t take risk to go into that triangle. Of course, Liaoning can’t go outside the maneuver region. Please figure out a route for Liaoning to reach its destination as soon as possible.

Input

There are no more than 3030 test cases.

For each case:

The first line is an integer n(2n20),n( 2 \leq n \leq 20), meaning that the maneuver region is an n×nn\times n grid.

The seconds line contains six float numbers x1,y1,x2,y2,x3,y3(100x1,y1,x2,y2,x3,y3100)x_1,y_1,x_2,y_2,x_3,y_3( -100 \leq x_1,y_1,x_2,y_2,x_3,y_3 \leq 100) which have at most 22 digits after the decimal point, indicating the coordinates of the vertices of Bermuda Triangle are (x1,y1),(x2,y2)(x_1,y_1), (x_2,y_2) and (x3,y3).(x_3,y_3). Liaoning ship can’t go into that triangle, but going along its edges or touching its vertices are allowed.

Then an n×n character matrix consists of ‘.’ and ‘#’ follows, indicating the weather condition of all check points. ‘.’ Means good weather and ‘#’ means bad weather. The bottom-left character stands for the weather of check point (0,0),(0,0), the character on the right side of it stands for (1,0),(1,0), and the upper-right character stands for (n1,n1).(n-1,n-1).

It is guaranteed that check point (0,0)(0,0) is not inside the Bermuda Triangle or on the edges of the triangle.

Output

For each test case, print the minimum days Liaoning ship needs to reach its destination. If it is impossible for Liaoning to reach its destination, print -1 instead.

Sample Input

3
0.5 1.5 1.5 1.5 1 0.5
.#.
...
..#
3
0.5 1.5 1.5 1.5 1 0.5
.#.
..#
..#

Sample Output

3
-1

題意

  • 就是說有一個地圖,你需要從(0,0)(0,0)走到(n1,n1)(n-1,n-1),每次你可以向相鄰的八個整點沿直線走,時間花費都是11,不能走到’#'中,而且走的路徑不能到達給定的一個三角形中,但是可以沿着三角形的一條邊走或者經過一個頂點,然後求最小的從(0,0)(0,0)走到(n1,n1)(n-1,n-1)的時間

題解

  • nn很小,考慮暴力找出所有可行路徑然後bfsbfs
  • 重點以及難點就是判斷一條路徑ses\rightarrow e是否與ABC\triangle ABC在內部有公共點,步驟如下
    • 首先如果兩個點ssee都在ABC\triangle ABC內部的話(可以根據三個小三角形面積之和等於大三角形面積),進一步判斷一下兩個點是否都在三角形的某一條邊上,如果是,則合法,否則不合法
    • 現在主要考慮枚舉三角形的每一條邊與ses\rightarrow e求交,如果沒有交點或者平行或者重合,繼續枚舉,否則剩下的情況就是不平行而且相交的情況,求出交點,如果交點intersectintersect不等於任何一個線段端點,這時可以直接判定在三角形內部有公共點,那麼顯然不合法,否則的話如果交點等於三角形的一個頂點,那麼也就是下圖這種情況
      在這裏插入圖片描述
      在這裏插入圖片描述
      直接判斷CBA\angle CBACBe\angle CBe大小即可判斷是否相交

代碼

#include<bits/stdc++.h>
using namespace std;
const double eps=1e-8;
const int maxn=50;
#define pi acos(-1.0)
int sgn(double k) {return k<-eps?-1:(k<eps?0:1);}
double Acos(double k) {return k>=1?0:(k<=-1?pi:acos(k));}
double Sqrt(double k) {return sgn(k)<=0?0:sqrt(k);}
char s[maxn][maxn];
bool vis[maxn][maxn];
bool ok[25][25][25][25];
int n,dir[8][2]={{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0}};

struct point{
    double x,y;
    point(double a=0,double b=0) {x=a;y=b;}
    point operator+(point other) {return point(x+other.x,y+other.y);}
    point operator-(point other) {return point(x-other.x,y-other.y);}
    point operator*(double k) {return point(x*k,y*k);}
    friend bool operator==(const point &p1,const point &p2) {return sgn(p1.x-p2.x)==0&&sgn(p1.y-p2.y)==0;}
    double operator*(point other) {return x*other.x+y*other.y;}
    double operator^(point other) {return x*other.y-y*other.x;}
    friend double area(point a,point b,point c) {return fabs((b-a)^(c-a))/2;}
    friend int point_to_line(point p,point s,point e) {return -sgn((e-s)^(p-s));}
    friend double len(point p) {return Sqrt(p.x*p.x+p.y*p.y);}
    friend double angle(point p1,point p2) {
        if(point_to_line(p2,point(0,0),p1)<=0) return Acos((p1*p2)/len(p1)/len(p2));
        return 2*pi-Acos((p1*p2)/len(p1)/len(p2));
    }
};

struct line{
    point s,e;
    line () {}
    line (point a,point b) {s=a;e=b;}
    friend point intersect(line l1,line l2) {
        double k=((l2.e-l2.s)^(l2.s-l1.s))/((l2.e-l2.s)^(l1.e-l1.s));
        return l1.s+(l1.e-l1.s)*k;
    }
    friend bool onseg(point p,line l) {
        return sgn((l.s-p)^(l.e-p))==0&&sgn((l.s-p)*(l.e-p))<=0;
    }
    friend int seg_to_seg(line l1,line l2) {
        if(sgn((l1.e-l1.s)^(l2.e-l2.s))==0) {
            if(onseg(l1.s,l2)||onseg(l1.e,l2)||onseg(l2.s,l1)||onseg(l2.e,l1)) return 1;
            return 0;
        }
        point inter=intersect(l1,l2);
        if(onseg(inter,l1)&&onseg(inter,l2)) return 3;
        return 2;
    }
    friend bool onright(point p,line l) {return ((l.e-l.s)^(p-l.s))<=0;}
};

point p[3];
line l[3];
struct node{int x,y,step;};
bool valid(int x,int y) {return x>=0&&x<=n-1&&y>=0&&y<=n-1&&s[x][y]!='#'&&!vis[x][y];}
int bfs() {
    memset(vis,false,sizeof(vis));
    queue<node> que;
    if(s[0][0]=='#'||s[n-1][n-1]=='#') return -1;
    que.push(node{0,0,0});
    vis[0][0]=true;
    while(!que.empty()) {
        node cur=que.front();que.pop();
        for(int i=0;i<8;i++) {
            int nxtx=cur.x+dir[i][0],nxty=cur.y+dir[i][1];
            if(valid(nxtx,nxty)&&ok[cur.x][cur.y][nxtx][nxty]) {
                vis[nxtx][nxty]=true;
                que.push(node{nxtx,nxty,cur.step+1});
                if(nxtx==n-1&&nxty==n-1) return cur.step+1;
            }
        }
    }
    return -1;

}

bool point_in_triangle(point p,point a,point b,point c) {
    return sgn(area(p,a,b)+area(p,b,c)+area(p,c,a)-area(a,b,c))==0;
}

bool zhongjian(point p,point a,point o,point b) {
    double k1=angle(b-o,p-o);
    double k2=angle(b-o,a-o);
    return sgn(k1)>0&&sgn(k1-k2)<0;
}

bool check(int a,int b,int c,int d) {
    bool ok1=a>=0&&a<=n-1&&b>=0&&b<=n-1&&c>=0&&c<=n-1&&d>=0&&d<=n-1&&s[a][b]!='#'&&s[c][d]!='#';
    if(!ok1) return false;
    point p1=point(a,b),p2=point(c,d);
    if(point_in_triangle(p1,p[0],p[1],p[2])&&point_in_triangle(p2,p[0],p[1],p[2]))  {
        bool ok=false;
        for(int i=0;i<=2;i++) if(onseg(p1,l[i])&&onseg(p2,l[i])) {ok=true;break;}
        return ok;
    }
    for(int i=0;i<=2;i++) {
        int k=seg_to_seg(line(p1,p2),l[i]);
        if(k==3){
            point inter=intersect(line(p1,p2),l[i]);
            if(!(inter==p1||inter==p2||inter==l[i].s||inter==l[i].e)) return false;
            else if(inter==p[i]) {
                if(inter==p1||inter==p2) continue;
                if(zhongjian(p1,p[((i-1)+3)%3],p[i],p[(i+1)%3])||zhongjian(p2,p[((i-1)+3)%3],p[i],p[(i+1)%3])) return false;
            }
        }
    }
    return true;
}

int main() {
    while(~scanf("%d",&n)) {
        memset(ok,false,sizeof(ok));
        for (int i = 0; i <= 2; i++) scanf("%lf %lf",&p[i].x,&p[i].y);
        if(onright(p[2],line(p[0],p[1]))) swap(p[1],p[2]);
        for(int i=0;i<=2;i++) l[i]=line(p[i],p[(i+1)%3]);
        for(int j=n-1;j>=0;j--) for(int i=0;i<=n-1;i++) scanf(" %c",&s[i][j]);
        for(int i=0;i<=n-1;i++) {
            for(int j=0;j<=n-1;j++) {
                for (int k = 0; k < 8; k++) {
                    int nxtx =i+dir[k][0],nxty=j+dir[k][1];
                    if(check(i,j,nxtx,nxty)) {
                        ok[i][j][nxtx][nxty]=ok[nxtx][nxty][i][j]=true;
                    }
                }
            }
        }
        printf("%d\n",bfs());
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章