UVA10514 River Crossing

River Crossing
Input: 
Standard Input

Output: Standard Output

A group of travelers have reached a river, which they intend to cross by building a small raft. However, they're terrified of the water as they can't swim, and they fear the raft might break apart any moment while they're using it. So, they would like to cross the river by traveling as little as possible over water. The river also contains some islands. They can use the raft to reach an island and then carry the raft over land and leave the island at some other point. The picture bellow shows a possible scenario. The shortest distance, counting only the distance over water, is shown with black straight lines (red for online contestants) on the river.

Write a program which, given the shape of the river (two sequences of connected line segments) and the islands (simple polygons), calculates the shortest distance required to travel over water in order to cross the river. The travelers must cross the river within the area of the map.

Input

The input consists of several scenarios. The first line contains the number of scenarios (at most 20). Next follows each scenario.

Each scenario starts with a line containing three integers: r1r2 (2 <= r1r2 <= 100) and n (0 <= n <= 11). Then follows r1 pair of integers, describing the coordinates (x,y) of one river bank. This is followed by another r2 pair of integers, describing the other river bank. The two river banks will not intersect nor touch each other.

Next follows the description of n island. Each island description starts with an integer m (3 <= m <= 20), the number of vertices in the polygon. Then follows m pairs of integers describing the coordinates (x,y) of the polygon, either in clockwise or counter clockwise direction. All islands will be simple polygons that lie between the two river banks, and they will neither overlap nor touch each other or the river banks.

All coordinates in the input will be between 0 and 10,000, inclusive. The two sequences of line segments describing the riverbanks will both start at x-coordinate 0 and end at same positive x-coordinate. All other x-coordinates in the input for that scenario, including those for the islands, will have x-coordinates between these two endpoints.

All integers in the input will be separated by at least one space or new line.

Output

For each scenario, output on a line by itself the shortest distance that must be travelled on water to cross the river. The precision should be to 3 decimal places, correctly rounded.

Sample Input

2
 
15 14 4
0 9 7 7 10 7 16 11 20 12 24 11 25 9 24 4 25 2 31 1 38 3 41 11 44 15 49 17 51 17
0 19 3 20 8 19 11 19 15 21 21 23 25 23 26 20 26 18 34 19 37 21 42 23 47 24 51 24
4
5 11 9 11 7 15 4 14
3
17 14 16 16 19 17
3
28 15 33 13 30 17
6
31 5 27 7 29 12 31 8 35 9 34 6
 
2 2 0
0 0 1000 0
0 100 1000 100
 

Sample Output

6.256
100.000


最短水上距离

多边形抽象成点,第i个与第j个多边形建边,取点到线段最短距离,最后跑一遍最短路OK

#define DeBUG
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <string>
#include <set>
#include <sstream>
#include <map>
#include <list>
#include <bitset>
using namespace std ;
#define zero {0}
#define INF 0x3f3f3f3f
#define EPS 1e-6
#define TRUE true
#define FALSE false
typedef long long LL;
const double PI = acos(-1.0);
//#pragma comment(linker, "/STACK:102400000,102400000")
inline int sgn(double x)
{
    return fabs(x) < EPS ? 0 : (x < 0 ? -1 : 1);
}
#define N 50
template<class T> T sqr(T x)//求平方
{
    return x * x;
}
// Point class
struct Point;
typedef Point Vec;
struct Point
{
    double x, y;
    Point () {}
    Point(double a, double b)
    {
        x = a;
        y = b;
    }
};

Vec operator + (const Vec &a, const Vec &b) //点加法
{
    return Vec(a.x + b.x, a.y + b.y);
}
Vec operator - (const Vec &a, const Vec &b) //点减法
{
    return Vec(a.x - b.x, a.y - b.y);
}
Vec operator * (const Vec &a, const double &p) //点与常数相乘
{
    return Vec(a.x * p, a.y * p);
}
Vec operator / (const Vec &a, const double &p) //点除以常数
{
    return Vec(a.x / p, a.y / p);
}
bool operator < (const Vec &a, const Point &b) //平面直角坐标系中左下方的为小
{
    return a.x < b.x || (sgn(a.x - b.x) == 0 && a.y < b.y);
}
bool operator == (const Vec &a, const Point &b) //点相等判断
{
    return sgn(a.x - b.x) == 0 && sgn(a.y - b.y) == 0;
}
inline double ptDis(Point a, Point b)//点间距
{
    return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y));
}
inline double dotDet(Vec a, Vec b)//点乘
{
    return a.x * b.x + a.y * b.y;
}
inline double crossDet(Vec a, Vec b)//叉乘
{
    return a.x * b.y - a.y * b.x;
}
inline double crossDet(Point o, Point a, Point b)//向量叉乘
{
    return crossDet(a - o, b - o);
}
inline double vecLen(Vec a)//求一点到原点距离
{
    return sqrt(dotDet(a, a));
}
double pt2Seg(Point x, Point a, Point b)//x在线段ab上的投影,这里保证为正
{
    if (a == b) return vecLen(x - a);
    Vec v1 = b - a, v2 = x - a, v3 = x - b;
    if (sgn(dotDet(v1, v2)) < 0) return vecLen(v2);
    if (sgn(dotDet(v1, v3)) > 0) return vecLen(v3);
    return fabs(crossDet(v1, v2)) / vecLen(v1);
}
std::vector<Point> land[N];
double mp[N][N];
int n;
double mindist(int x, int y)
{
    double minn = INF;
    for (int i = 0; i < land[x].size(); i++)
    {
        for (int j = 0; j < land[y].size() - 1; j++)
        {
            double t = pt2Seg(land[x][i], land[y][j], land[y][j + 1]);
            minn = min(t, minn);
        }
    }
    for (int i = 0; i < land[y].size(); i++)
    {
        for (int j = 0; j < land[x].size() - 1; j++)
        {
            double t = pt2Seg(land[y][i], land[x][j], land[x][j + 1]);
            minn = min(t, minn);
        }
    }
    return minn;
}
void build()
{
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            mp[i][j] = INF;
        }
    }
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            if (i != j)
                mp[i][j] = mp[j][i] = mindist(i, j);
            else
                mp[i][j] = 0;
        }
    }
}

double SPFA(int s, int e)
{
    double price[N];
    // memset(price, INF, sizeof(price));
    fill(price, price + N, INF);
    bool inq[N] = zero;
    price[s] = 0;
    queue<int>Q;
    Q.push(s);
    int u;
    double tmp;
    while (!Q.empty())
    {
        u = Q.front();
        Q.pop();
        inq[u] = false;
        for (int v = 0; v < n; v++)
        {
            tmp = price[u] + mp[u][v];
            if (price[v] > tmp)
            {
                price[v] = tmp;
                if (!inq[v])
                {
                    inq[v] = true;
                    Q.push(v);
                }
            }
        }
    }
    return price[e];
}
int main()
{
#ifdef DeBUGs
    freopen("C:\\Users\\Sky\\Desktop\\1.in", "r", stdin);
#endif
    int T;
    scanf("%d", &T);
    int r1, r2;
    while (T--)
    {
        for (int i = 0; i < 30; i++)
            land[i].clear();
        double x, y;
        scanf("%d%d%d", &r1, &r2, &n);
        for (int i = 0; i < r1; i++)
        {
            scanf("%lf%lf", &x, &y);
            land[0].push_back(Point(x, y));
        }
        for (int i = 0; i < r2; i++)
        {
            scanf("%lf%lf", &x, &y);
            land[1].push_back(Point(x, y));
        }
        n += 2;
        for (int i = 2; i < n; i++)
        {
            int m;
            scanf("%d", &m);
            for (int j = 0; j < m; j++)
            {
                scanf("%lf%lf", &x, &y);
                land[i].push_back(Point(x, y));
            }
            land[i].push_back(land[i][0]);
        }
        build();
        printf("%.3lf\n", SPFA(0, 1));
    }

    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值