E - The Doors POJ - 1556 計算幾何+最短路

題意:每列有兩個門(即有四個端點)問你最短路是多少

題解:因爲只能走端點,所以根據端點建圖跑最短路就可以了

端點連不連通看這兩個端點之間有沒有牆,即線段是不是規範相交

#include <iostream>
#include <stdio.h>
#include <cmath>
#include <vector>
using namespace std;
#define maxn int(1e3+5)
const double eps = 1e-8;
const double INF = 1e9;
const double pi = acos (-1.0);
  
int dcmp (double x) {
    if (fabs (x) < eps) return 0;
    return (x < 0 ? -1 : 1);
}
inline double sqr (double x) {return x*x;}
 
//*************點
struct Point {
    double x, y;
    Point (double _x = 0, double _y = 0):x(_x), y(_y) {}
    void input () {scanf ("%lf%lf", &x, &y);}
    void output () {printf ("%.2f %.2f\n", x, y);}
    friend istream &operator >>(istream &os,Point &b){
        os>>b.x>>b.y;
        return os;
    }
    friend ostream &operator <<(ostream &os,Point &b){
        os<<b.x<<' '<<b.y;
        return os;
    }
    bool operator == (const Point &b) const {
        return (dcmp (x-b.x) == 0 && dcmp (y-b.y) == 0);
    }
    bool operator !=(const Point &b)const{
        return !((dcmp(x-b.x)==0&&dcmp(y-b.y)==0));
    }
    bool operator < (const Point &b) const {
        return (dcmp (x-b.x) == 0 ? dcmp (y-b.y) < 0 : x < b.x);
    }
    double operator ^(const Point &b)const{     //叉積
        return x*b.y-y*b.x;
    }
    Point operator + (const Point &b) const {
        return Point (x+b.x, y+b.y);
    }
    Point operator - (const Point &b) const {
        return Point (x-b.x, y-b.y);
    }
    Point operator * (double a) {
        return Point (x*a, y*a);
    }
    Point operator / (double a) {
        return Point (x/a, y/a);
    }
    double len2 () {//返回長度的平方
        return sqr (x) + sqr (y);
    }
    double len () {//返回長度
        return sqrt (len2 ());
    }
    double polar(){ //向量的極角
        return atan2(y,x);   //返回與x軸正向夾角(-pi~pi]
    }
    Point change_len (double r) {//轉化爲長度爲r的向量
        double l = len ();
        if (dcmp (l) == 0) return *this;//零向量返回自身
        r /= l;
        return Point (x*r, y*r);
    }
    Point rotate_left () {//順時針旋轉90度
        return Point (-y, x);
    }
    Point rotate_right () {//逆時針旋轉90度
        return Point (y, -x);
    }
    Point rotate (Point p, double ang) {//繞點p逆時針旋轉ang
        Point v = (*this)-p;
        double c = cos (ang), s = sin (ang);
        return Point (p.x + v.x*c - v.y*s, p.y + v.x*s + v.y*c);
    }
    Point normal () {//單位法向量
        double l = len ();
        return Point (-y/l, x/l);
    }
};
  
double cross (Point a, Point b) {//叉積
    return a.x*b.y-a.y*b.x;
}
double dot (Point a, Point b) {//點積
    return a.x*b.x + a.y*b.y;
}
double dis (Point a, Point b) {//兩個點的距離
    Point p = b-a; return p.len ();
}
double rad_degree (double rad) {//弧度轉化爲角度
    return rad/pi*180;
}
double rad (Point a, Point b) {//兩個向量的夾角
    return fabs (atan2 (fabs (cross (a, b)), dot (a, b)) );
}
bool parallel (Point a, Point b) {//向量平行
    double p = rad (a, b);
    return dcmp (p) == 0 || dcmp (p-pi) == 0;
}
  
//************直線 線段
struct Line {
    Point s, e;//直線的兩個點
    Line () {}
    Line (Point _s, Point _e) : s(_s), e(_e) {}
    //一個點和傾斜角確定直線
    Line (Point p, double ang) {
        s = p;
        if (dcmp (ang-pi/2) == 0) {
            e = s + Point (0, 1);
        }
        else
            e = s + Point (1, tan (ang));
    }
    //ax+by+c=0確定直線
    Line (double a, double b, double c) {
        if (dcmp (a) == 0) {
            s = Point (0, -c/b);
            e = Point (1, -c/b);
        }
        else if (dcmp (b) == 0) {
            s = Point (-c/a, 0);
            e = Point (-c/a, 1);
        }
        else {
            s = Point (0, -c/b);
            e = Point (1, (-c-a)/b);
        }
    }
    void input () {
        s.input ();
        e.input ();
    }
    void adjust () {
        if (e < s) swap (e, s);
    }
    double polar(){ //極角
        return atan2(e.y-s.y,e.x-s.x);   //返回與x軸正向夾角(-pi~pi]
    }
    double length () {//求線段長度
        return dis (s, e);
    }
    double angle () {//直線的傾斜角
        double k = atan2 (e.y-s.y, e.x-s.x);
        if (dcmp (k) < 0) k += pi;
        if (dcmp (k-pi) == 0) k -= pi;
        return k;
    }
    Point operator &(const Line &b)const{    //求兩直線交點
        Point res=s;
        double t=((s-b.s)^(b.s-b.e))/((s-e)^(b.s-b.e));
        res.x+=(e.x-s.x)*t;
        res.y+=(e.y-s.y)*t;
        return res;
    }
};
  
int relation (Point p, Line l) {//點和直線的關係
    //1:在左側 2:在右側 3:在直線上
    int c = dcmp (cross (p-l.s, l.e-l.s));
    if (c < 0) return 1;
    else if (c > 0) return 2;
    else return 3;
}
  
bool point_on_seg (Point p, Line l) {//判斷點在線段上
    return dcmp (cross (p-l.s, l.e-l.s)) == 0 &&
    dcmp (dot (p-l.s, p-l.e) <= 0);
    //如果忽略端點交點改成小於號就好了
}
  
bool parallel (Line a, Line b) {//直線平行
    return parallel (a.e-a.s, b.e-b.s);
}
  
int seg_cross_seg (Line a, Line v) {//線段相交判斷//未驗證
    //1:規範相交 2:不規範相交 3:不相交
    
    int d1 = dcmp (cross (a.e-a.s, v.s-a.s));
    int d2 = dcmp (cross (a.e-a.s, v.e-a.s));
    int d3 = dcmp (cross (v.e-v.s, a.s-v.s));
    int d4 = dcmp (cross (v.e-v.s, a.e-v.s));
    if ((d1^d2) == -2 && (d3^d4) == -2) return 1;
    if( (d1 == 0 && dcmp (dot (v.s-a.s, v.s-a.e)) <= 0) ||
        (d2 == 0 && dcmp (dot (v.e-a.s, v.e-a.e)) <= 0) ||
        (d3 == 0 && dcmp (dot (a.s-v.s, a.s-v.e)) <= 0) ||
        (d4 == 0 && dcmp (dot (a.e-v.s, a.e-v.e)) <= 0))
        return 2;
    return 3;
}
int line_cross_seg (Line a, Line v) {//直線和線段相交判斷,a直線,v線段//已驗證
    //1:規範相交 2:非規範相交 3:不相交
    int d1 = dcmp (cross (a.s-a.e, v.s-a.e));
    int d2 = dcmp (cross (a.s-a.e, v.e-a.e));
    if (d1*d2 == -1) return 1;
    if(d1 == 0 || d2 == 0)return 2;
    else return 3;
}
double d[maxn][maxn];
Point a[maxn];
Line b[maxn];
int main () {
    int n;
	while(scanf("%d",&n)&&n!=-1){
		int tot=1,tot2=1;a[tot++]=Point(0,5);
		for(int i=1;i<=n;i++){
			double x;double y[6];
			scanf("%lf",&x);
			for(int j=1;j<=4;j++){
				scanf("%lf",&y[j]);
				a[tot++]=Point(x,y[j]);
			}
			y[0]=0;y[5]=10;
			for(int j=0;j<=5;j++){
				if(j%2==1){
					b[tot2++]=Line(Point(x,y[j]),Point(x,y[j-1]));
				}
			}
		}
		a[tot++]=Point(10,5);tot--;tot2--;
		for(int i=1;i<=tot;i++){
			for(int j=i;j<=tot;j++){
				if(i==j){d[i][j]=0;continue;}
				d[i][j]=INF;
				Line tmp=Line(a[i],a[j]);
				int flag=1;
				for(int k=1;k<=tot2;k++){
					if(seg_cross_seg(tmp,b[k])<=1){
						flag=0;
						break;
					}
				}
				if(flag)d[i][j]=d[j][i]=dis(a[i],a[j]);
			}
		}
		for(int k=1;k<=tot;k++){
			for(int i=1;i<=tot;i++){
				for(int j=1;j<=tot;j++){
					if(dcmp(d[i][j]-d[i][k]-d[k][j])>0){
						d[i][j]=d[i][k]+d[k][j];
					}
				}
			}
		}
		printf("%.2f\n",d[1][tot]);
	}
    return 0;	
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章