您的位置:首页 > 其它

POJ 1066 线段相交

2015-05-15 11:04 337 查看
题意:给出一些端点在边界上的线段,然后给出一个点,要求从点走到边界外面,跨过线段的时候要求必须从当前小线段的中点走

思路:刚开始想的很复杂,想先求出来每个小线段,然后跑最短路= =,后来写跪了,看了discuss,提供的一种思路是枚举边界上的点,然后求边界上的点和终点与线段相交的个数,取最小值。 看起来似乎很对的样子,然后敲了,A了,实际上还是不太懂= =,唉。。。

然后又看了看,大概可以这么想:

 1.从点A到终点T的线段直接跨过了n个线段,是否可能通过别的方式用少于n次到达终点?答案是不可能,可以把其余的线段都去掉,然后很容易发现必须通过n次才能到达

 2.从点A到终点的一个直线,能否转化成一个题中描述的折线?能,只要把各个交点都挪下位置就可以了

所以找到一个最小的直线,就能找到最小的折线

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<queue>
#include<list>
using namespace std;
const double INF = 1e200;
const double EP = 1e-8;
const int maxn = 4000;
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{///ax + by + c = 0&&a >= 0///一般式
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;}
}
};
double multiply(POINT sp,POINT ep,POINT op){///向量op->sp X op->ep的叉乘,小于0:ep在op->sp顺时针方向//大于0:0:ep在op->sp逆时针方向//等于0:三点共线
return ((sp.x - op.x)*(ep.y - op.y) - (ep.x - op.x)*(sp.y - op.y));
}
bool online(SEGMENT l,POINT p){///判断点是否在线段上
return ((multiply(l.e,p,l.s) == 0)&&(((p.x-l.s.x)*(p.x-l.e.x))<= 0)&&(((p.y-l.s.y)*(p.y-l.e.y)) <= 0));
}
bool intersect(SEGMENT u,SEGMENT v){///两线段相交(包括端点),返回true
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));
}
bool intersect_a(SEGMENT u,SEGMENT v){///两线段相交(不包括端点)
return ((intersect(u,v))&&
!online(u,v.s)&&
!online(u,v.e)&&
!online(v,u.e)&&
!online(v,u.s));
}
int lineintersect(LINE l1,LINE l2,POINT &p){///求两直线交点,有交点返回1和交点,没有返回0,重合返回2
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;
}
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));
}
///************************************************************************************************************************************
POINT pp[maxn];
int n;
SEGMENT seg[maxn];
int get_num(SEGMENT ss){
int nn = 0;
for(int i = 0;i < n;i ++){
if(intersect_a(ss,seg[i]))nn++;
}//cout<<nn<<endl;
return nn;
}
int main(){
//freopen("in.txt","r",stdin);
cin>>n;
for(int i = 0;i < n;i ++){
double a,b,c,d;
cin>>a>>b>>c>>d;
pp[2*i].x = a;
pp[2*i].y = b;
pp[2*i+1].x = c;
pp[2*i+1].y = d;
seg[i].s = pp[2*i];
seg[i].e = pp[2*i+1];
}
pp[2*n].x = 0,pp[2*n].y = 0;
pp[2*n+1].x = 0,pp[2*n+1].y = 100;
pp[2*n+2].x = 100,pp[2*n+2].y = 0;
pp[2*n+3].x = 100,pp[2*n+3].y = 100;
double tx,ty;
cin>>tx>>ty;
POINT t(tx,ty);
int ans = 1000000;
for(int i = 0;i < 2*n+4;i ++){
SEGMENT now(t,pp[i]);
ans = min(ans,get_num(now));
}
cout<<"Number of doors = "<<ans+1<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: