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: r1, r2 (2 <= r1, r2 <= 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;
}