题意:
求穿越对角线为(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的同侧,则不想交
求穿越对角线为(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;
}