POJ 1556 (平面几何 最短路)

题目链接:点击这里

题意:给出一个图, 求从起点走到终点的最短路.

格子比较少, 直接把所有的格子坐标都扔进数组里然后暴力枚举两个点之间有没有线段挡着, 用距离建图跑最短路.

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;

const double eps = 1e-8;
const double INF = 1e20;
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);}
    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);
    }
    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 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 ();
}

//************直线 线段
struct Line {
    Point s, e;//直线的两个点
    Line () {}
    Line (Point _s, Point _e) : s(_s), e(_e) {}
    void input () {
        s.input ();
        e.input ();
    }
};
int seg_cross_seg (Line a, Line v) {//线段相交判断
    //2:规范相交 1:不规范相交 0:不相交
    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 2;
    return (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);
}

#define maxn 11111

struct node {
    int v, next;
    double w;
}edge[maxn];
int cnt, head[maxn];
int n;
Line l[maxn];
Point p[maxn];
int cnt_l, cnt_p, id[maxn];//点i属于那一条线段
double cur[5], d[maxn];

bool vis[maxn];
int top, num[maxn];
bool spfa (int start, double *d, int n) {
    memset (vis, 0, sizeof vis);
    for (int i = 0; i < n; i++) {
        d[i] = INF;
    }
    vis[start] = 1;
    d[start] = 0;
    queue <int> q;
    while (!q.empty ()) q.pop ();
    q.push (start);
    memset (num, 0, sizeof num);
    num[start] = 1;
    while (!q.empty ()) {
        int u = q.front (); q.pop ();
        vis[u] = 0;
        for (int i = head[u]; i != -1; i = edge[i].next) {
            int v = edge[i].v;
            if (d[v]>d[u]+edge[i].w) {
                d[v] = d[u]+edge[i].w;
                if (!vis[v]) {
                    vis[v] = 1;
                    q.push (v);
                    if (++num[v] > n)
                        return 0;
                }
            }
        }
    }
    return 1;
}

void add_edge (int u, int v, double w) {
    edge[cnt].v = v, edge[cnt].w = w, edge[cnt].next = head[u], head[u] = cnt++;
}

int main () {
    while (cin >> n && n != -1) {
        cnt_l = cnt_p = cnt = 0;
        memset (head, -1, sizeof head);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < 5; j++) cin >> cur[j];
            for (int j = 1; j < 5; j++) id[cnt_p] = cnt_l+j/2, p[cnt_p++] = Point (cur[0], cur[j]);
            l[cnt_l++] = Line (Point (cur[0], 0), Point (cur[0], cur[1]));
            l[cnt_l++] = Line (Point (cur[0], cur[2]), Point (cur[0], cur[3]));
            l[cnt_l++] = Line (Point (cur[0], cur[4]), Point (cur[0], 10));
        }
        int s, t;
        s = cnt_p; p[cnt_p++] = Point (0, 5);
        t = cnt_p; p[cnt_p++] = Point (10, 5);
        for (int i = 0; i < cnt_p; i++) {
            for (int j = 0; j < cnt_p; j++) if (j != i) {
                bool flag = 0;
                for (int k = 0; k < cnt_l; k++) if (k != id[i] && k != id[j]) {
                    if (seg_cross_seg (Line (p[i], p[j]), l[k])) {
                        flag = 1;
                        break;
                    }
                }
                if (!flag) {
                    add_edge (i, j, dis (p[i], p[j]));
                }
            }
        }
        spfa (s, d, cnt_p);
        printf ("%.2f\n", d[t]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值