您的位置:首页 > 其它

POJ 1556 线段与线段相交 + dijkstra

2015-05-14 19:06 274 查看
题意:一个10*10 的地图,在竖着的方向上有n个列被放置了木板,每列三个,也就是产生了两个空隙,如图,很好理解 = =

思路:首先这道题要求最短路,最后肯定是跑一个最短路,之前的建图比较麻烦,把每个列的点都存下来的话,判断两个点之间能否建边就是这个线段与其他的3*n个线段均不相交,然后建图(刚开始没存点差点没建死= =)!

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<queue>
using namespace std;
const double INF = 1e200;
const double EP = 1e-8;
const int maxn = 5100;
const double PI = acos(-1);
struct POINT{
double x;
double y;
POINT(double a = 0,double b = 0){x = a;y = b;}
};///点 定义
struct SEGMENT{///line segment
POINT s;
POINT e;
SEGMENT(POINT a,POINT b){s = a;e = b;}
SEGMENT(){}
};///线段 定义
struct LINE{
double a;
double b;
double c;
LINE(double da,double db,double dc){a = da;b = db;c = dc;}///一般式
LINE(double x1,double y1,double x2,double y2){///根据两个点求出一般式
a = y1 - y2;b = x2 - x1;c = x1*y2 - x2*y1;
if(a < 0){a*=-1;b*=-1;c*=-1;}
}
};///ax + by + c = 0&&a >= 0
int multiply(POINT sp,POINT ep,POINT op){
return ((sp.x - op.x)*(ep.y - op.y) - (ep.x - op.x)*(sp.y - op.y));
}///向量op->sp X op->ep的叉乘,小于0:ep在op->sp顺时针方向//大于0:0:ep在op->sp逆时针方向//等于0:三点共线
bool intersect(SEGMENT u,SEGMENT v){
return ((max(u.s.x,u.e.x) >= min(v.s.x,v.e.x))&&
(max(v.s.x,v.e.x) >= min(u.s.x,u.e.x))&&
(max(u.s.y,u.e.y) >= min(v.s.y,v.e.y))&&
(max(v.s.y,v.e.y) >= min(u.s.y,u.e.y))&&
(multiply(v.s,u.e,u.s)*multiply(u.e,v.e,u.s) >= 0)&&
(multiply(u.s,v.e,v.s)*multiply(v.e,u.e,v.s) >= 0));
}///相交(包括端点),返回true
int lineintersect(LINE l1,LINE l2,POINT &p){
double d = l1.a*l2.b-l2.a*l1.b;
double d2 = l1.a*l2.c-l2.a*l1.c;
double d3 = l1.b*l2.c-l2.b*l1.c;
if(fabs(d) < EP&&fabs(d2) < EP&&fabs(d3) < EP)return 2;
p.x = (l2.c*l1.b-l1.c*l2.b)/d;
p.y = (l2.a*l1.c-l1.a*l2.c)/d;
if(fabs(d) < EP)return 0;
return 1;
}///求两直线交点,有交点返回1和交点,没有返回0,重合返回2
double point_dis(POINT a,POINT b){
return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
}
///************************************************************************************************************************************
struct Side{
int v;
double w;
int next;
}side[2000];
struct Node{
int u;
double dis;
int next;
friend bool operator < (Node a,Node b){
return a.dis > b.dis;
}
};
int top;
int node[1000];
void add_side(int u,int v,double w){
side[top] = (Side){v,w,node[u]};
node[u] = top++;
}
int n;
SEGMENT seg[50];
POINT pp[200];
priority_queue<Node>q;
double dis[1000];
double dijkstra(){
q.push((Node){0,0});
for(int i = 0;i < 1000;i ++)dis[i] = INF;
while(!q.empty()){
Node now = q.top();q.pop();
if(dis[now.u] != INF)continue;
dis[now.u] = now.dis;
for(int i = node[now.u];i != -1;i = side[i].next){
q.push((Node){side[i].v,dis[now.u] + side[i].w});
}
}
return dis[4*n+1];
}
bool equal_point(POINT a,POINT b){
return (fabs(a.x - b.x) < EP&&fabs(a.y - b.y) < EP);
}
bool ok(POINT A,POINT B){
SEGMENT ss(A,B);
for(int i = 0;i < 3*n;i ++){
if(equal_point(A,seg[i].s)||equal_point(A,seg[i].e)||equal_point(B,seg[i].s)||equal_point(B,seg[i].e))continue;
if(intersect(ss,seg[i]))return false;
}
return true;
}
int main(){
//freopen("in.txt","r",stdin);
while(cin>>n){
if(n == -1)break;
memset(node,-1,sizeof(node));
top = 0;
double x,y1,y2,y3,y4;
POINT S(0,5),E(10,5);
for(int i = 0;i < n;i ++){
cin>>x>>y1>>y2>>y3>>y4;
POINT a,b,c,d,e,f;
a.x = b.x = c.x = d.x = e.x = f.x = x;
a.y = 0;b.y = y1;c.y = y2;d.y = y3;e.y = y4;f.y = 10;
pp[i*4] = b;pp[i*4+1] = c;pp[i*4+2] = d;pp[i*4+3] = e;
seg[i*3].s = a,seg[i*3].e = b;
seg[i*3+1].s = c,seg[i*3+1].e = d;
seg[i*3+2].s = e,seg[i*3+2].e = f;
}
if(ok(S,E)){
printf("10.00\n");
continue;
}
for(int i = 0;i < 4*n; i++){
if(ok(S,pp[i]))add_side(0,i+1,point_dis(S,pp[i]));
}
for(int i = 0;i < 4*n;i ++){
if(ok(E,pp[i]))add_side(i+1,n*4+1,point_dis(E,pp[i]));
}
for(int i = 0;i < 4*n;i ++){
for(int j = i/4*4+4;j < 4*n;j ++){
if(ok(pp[i],pp[j]))add_side(i+1,j+1,point_dis(pp[i],pp[j]));
}
}
// for(int i = 0;i <= 4*n;i ++){
// cout<<i<<':';
// for(int j =node[i];j != -1;j = side[j].next)cout<<side[j].v<<' ';
// cout<<endl;
// }
double ans = dijkstra();
printf("%.2f\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息