Poj 1556 The Doors

题意:
求穿越对角线为(0,0,10,10)矩形的(0,5)到(10,5)的最短路径


        在矩形里面存在竖直的墙体, 没个墙上在上面开了两个口:用5个参数描述x,y1, y2, y3, y4
x为墙的x坐标,y1-y4为从下到上的缺口端点


方法: 以所有墙的墙角(缺口处)和起始两点为顶点,建立无向图。
建图过程中需要判断两条线段是否相交。


=》知识点:最短路 + 线段相交判定。 最短路用Dijkstar即可


判断线段相交: 利用叉积(相乘大于零逆时针)
1.如果Line1的两个顶点在Line2的同侧,则不相交
2.若1不成立,判断Line2的两个顶点在Line1的同侧,则不想交

3.若2不成立,则线段相交


#include <cstdio>
#include <cstring>
#include <string>
#include <string>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#define MAX 10005
#define INF 100000000
#define PI acos(-1.0)
#include <iostream>
using namespace std;
//0ms 1Y
struct Vector2d
{
    double x, y;
    Vector2d(){}
    Vector2d(double xx, double yy){ x =  xx; y = yy;}
    Vector2d(const Vector2d &v){x = v.x; y = v.y;};
    double crossMul(const Vector2d &vec)const{
        //Vector2d ans((x * vec.y), (y * vec.x));
        return (x * vec.y) -  (y * vec.x);
    }
    Vector2d sub(const Vector2d &point)const{
        Vector2d ans(x - point.x, y - point.y);
        return ans;
    }
    double getLength()const{
        return sqrt(x * x + y * y);
    }
    void output(){
        cout<<x<<" "<<y<<endl;
    }

};
struct Line
{
    Vector2d p1;
    Vector2d p2;
    Line(){}
    Line(const Vector2d &mp1, const Vector2d &mp2):p1(mp1), p2(mp2){}
    bool isInsect(const Line &line)const{
        Vector2d va = line.p1.sub(p1), vb = line.p1.sub(p2);
        double cmRes1 = va.crossMul(vb);
        va = line.p2.sub(p1); vb  = line.p2.sub(p2);
        double cmRes2 = va.crossMul(vb);
        if(cmRes1 == 0 || cmRes2 == 0)return true;
        if( (cmRes1 > 0 && cmRes2 > 0) || (cmRes1 < 0 && cmRes2 < 0) )///同号不想交
            return false;

        va = p1.sub(line.p1); vb = p1.sub(line.p2 );
        cmRes1 = va.crossMul(vb);
        va = p2.sub(line.p1); vb = p2.sub(line.p2);
        cmRes2 = va.crossMul(vb);
        if(cmRes1 == 0 || cmRes2 == 0)return true;
         if( (cmRes1 > 0 && cmRes2 > 0) || (cmRes1 < 0 && cmRes2 < 0) )///同号不相交
            return false;
        return true;
    }

    double getLength(){
        return p1.sub(p2).getLength();
    }
};
struct Wall
{
    double x, y1, y2, y3, y4;
    void input(){
        cin>>x>>y1>>y2>>y3>>y4;
    }
    Vector2d getPoint(int index)const{
        Vector2d vec;
        vec.x = x;
        switch(index){
            case 1:
                vec.y = y1;break;
            case 2:
                vec.y = y2; break;
            case 3:
                vec.y = y3; break;
            case 4:
                vec.y = y4; break;
            default:
                puts("index outof bounds");
                break;
        }
        return vec;
    }
}walls[MAX];
struct Edge
{
    int pos, next;
    double val;
}edge[MAX * 2];
int N, vN;
int head[MAX], e;
Vector2d start(0, 5);
Vector2d end(10, 5);
bool isCanLink(const int &ii, const int &i, Vector2d &pNow , Vector2d &pTest);
void insert(int a, int b,  double val){
    edge[e].next = head[a];
    edge[e].pos = b;
    edge[e].val = val;
    head[a] = e++;
}
void showMap(){
    for(int i = 0;  i < vN; i++){
        int next = head[i], pos;
        printf("head : %d\n", i);
        while(next != -1){
            pos = edge[next].pos;
            cout<<pos<<"->"<<edge[next].val<<":::";
            next = edge[next].next;
        }cout<<endl;

    }
}

void init(){
    e = 0;
    memset(head, -1, sizeof(head));
    vN = N * 4 + 2;//0 - (vN - 1)
    for(int i = 0; i < N; i++){
            walls[i].input();
    }//end input
}
void makeMap(){//O(vN^2)

    Vector2d pNow, pTest;
    Line line;
    for(int i= 0;i < N; i++){
        for(int j = 1; j <= 4; j++ ){
            pNow = walls[i].getPoint(j);
//            puts("pNow get");
            for(int ii  = i - 1; ii >= 0; ii--){
                for(int jj = 1; jj <= 4; jj++){
                    pTest = walls[ii].getPoint(jj);
//                    puts("pTest get");
                    if(isCanLink(ii, i, pNow, pTest)){
                        int a = i * 4 + j, b = ii * 4 + jj;
                        line.p1 = pNow;
                        line.p2 = pTest;
                        double val = line.getLength();
                        insert(a, b, val);
                        insert(b, a, val);
                    }
                }
            }//之前检测完毕
            line.p1 = pNow;
            line.p2 = start;
            if(isCanLink(-1, i, pNow, start)){
                int a = i * 4 + j, b = 0;
                double val = line.getLength();
                insert(a, b, val);
                insert(b, a, val);
            }
         }
    }//全部线段之前检测完毕
//      puts("end point left");
      pNow = end;
      for(int ii  = N - 1; ii >= 0; ii--){
                for(int jj = 1; jj <= 4; jj++){
                    pTest = walls[ii].getPoint(jj);
                    if(isCanLink(ii, N, pNow, pTest)){
                        int a = ii * 4 + jj, b = vN - 1;
                        line.p1  = pNow;
                        line.p2 =  pTest;
                        double val = line.getLength();
                        insert(a, b, val);
                        insert(b, a, val);
                    }
                }
      }//最后之前一点检测完毕

      if(isCanLink(-1, N, start, end)){
            int a = 0, b = vN - 1;
            double val = start.sub(end).getLength();
            insert(a, b, val);
            insert(b, a, val);
      }//全部点处理完毕
}

bool isCanLink(const int &ii, const int &i, Vector2d &pNow , Vector2d &pTest){
    Line line1(pNow, pTest), line2;
//    puts("judge : ");
//    pNow.output();pTest.output();
    for(int ptr = i  - 1; ptr > ii ; ptr --){
        int canPass = 2;
        for(int j = 1; j <= 4; j+= 2){
            line2.p1 = walls[ptr].getPoint(j);
            line2.p2 = walls[ptr].getPoint(j + 1);
            if(!line1.isInsect(line2)){//不过缺口线段则不可连接
                canPass --;
//                printf("cannot Insect at %d: %d with lines\n", ptr, j);
//                line1.p1.output();line1.p2.output();
//                line2.p1.output();line2.p2.output();
//                puts("end");
            }
        }
        if(canPass == 0){

            return false;
        }
    }
//    puts("can link");
    return true;
}

void dijkstra(){
    double d[MAX];
    bool v[MAX];
    for(int i = 0; i < vN; i++){
        d[i] = INF; v[i] = false;
    }
    d[0] = 0;
    double min_d;
    int index;
    for(int i  = 0; i < vN - 1; i++){
        min_d = INF; index = -1;
        for(int j = 0; j < vN; j++){
            if(!v[j] && min_d > d[j]){
                min_d = d[j];
                index = j;
            }
        }
        if(index != -1){
            v[index] = true;
            int next = head[index], pos;
            while(next != -1){
                pos = edge[next].pos;
                if(!v[pos]){
                    double dist = d[index] + edge[next].val;
                    if(d[pos] > dist)d[pos] = dist;
                }
                next = edge[next].next;
            }
        }
    }
    printf("%.2f\n", d[vN -1]);
}
int main()
{
    while(cin>>N, N != -1){
        init();
//        puts("init end");
        makeMap();
//        showMap();
//        puts("makeMap end");
        dijkstra();
    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值