20149 선분 교차 3
20149 선분 교차 3 해법
백준 온라인 저지 사이트에 올라와있는 문제이다.
풀이 할 때 일반적으로 떠오르는 해법인 평면에서 직선의 방정식을 이용해 각 직선의 기울기 등을 계산하는 방식은 부동소수점 오차로 인해 정확한 풀이가 불가능하다. 따라서 벡터의 외적을 활용하는 ccw 알고리즘을 써야 한다.
이때 두 선분이 서로 일직선상에서 교차하는 경우에 대한 몇가지 예외처리까지 해주면 완전한 풀이가 가능하다.
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int ccw(long long x1,long long y1,long long x2,long long y2,long long x3,long long y3)
{
long long v_x1 = x2-x1,v_y1 = y2-y1,v_x2 = x3-x2,v_y2 = y3-y2;
long long ccw = v_x1*v_y2 - v_x2*v_y1;
if(ccw>0) return 1;
else if(ccw==0) return 0;
else return -1;
}
int main()
{
long long x1,x2,x3,x4,y1,y2,y3,y4;
scanf("%lld %lld %lld %lld\n%lld %lld %lld %lld",&x1,&y1,&x2,&y2,&x3,&y3,&x4,&y4);
int ccw1,ccw2,ccw3,ccw4;
ccw1 = ccw(x1,y1,x2,y2,x3,y3);
ccw2 = ccw(x1,y1,x2,y2,x4,y4);
ccw3 = ccw(x3,y3,x4,y4,x1,y1);
ccw4 = ccw(x3,y3,x4,y4,x2,y2);
bool result =false;
if(ccw1 * ccw2 == 0 && ccw3 * ccw4 == 0)
{
if(x1>x2)
{
swap(x1,x2);
swap(y1,y2);
}
else if(x1==x2 && y1>y2)
{
swap(x1,x2);
swap(y1,y2);
}
if(x3>x4)
{
swap(x3,x4);
swap(y3,y4);
}
else if(x3==x4 && y3>y4)
{
swap(x3,x4);
swap(y3,y4);
}
if((x2>x3?true:(x2==x3?y2>=y3:false))&&(x1<x4?true:(x1==x4?y1<=y4:false)))
{
printf("1\n");
if(ccw1!=ccw2 && ccw3!=ccw4)
{
if(x2==x3 && y2==y3 || x2==x4 && y2==y4) printf("%lld %lld",x2,y2);
else printf("%lld %lld",x1,y1);
}
else{
if(x2==x3 && y2==y3) printf("%lld %lld",x2,y2);
else if(x1==x4 && y1==y4) printf("%lld %lld",x1,y1);
}
return 0;
}
}
else if(ccw1 * ccw2 <= 0 && ccw3 * ccw4 <= 0)
{
printf("1\n");
long double grad1,grad2,c1,c2;
bool is_ver1=false,is_ver2=false;
if(x1-x2==0) is_ver1 =true;
else
{
grad1 = (long double)(y1-y2) / (x1-x2);
}
if(x3-x4==0) is_ver2=true;
else
{
grad2 = (long double)(y3-y4)/(x3-x4);
}
if(is_ver1)
{
c2 = y3 - grad2 * x3;
long double y_meet;
y_meet = grad2 * x1 + c2;
printf("%.16Lf %.16Lf",(long double)x1,y_meet);
}
else if(is_ver2)
{
c1 = y1 - grad1 * x1;
long double y_meet;
y_meet = grad1 * x3 + c1;
printf("%.16Lf %.16Lf",(long double)x3,y_meet);
}
else
{
c1 = y1 - grad1 * x1;
c2 = y3 - grad2 * x3;
long double x_meet,y_meet;
x_meet = (c2 - c1) / (grad1 - grad2);
y_meet = x_meet * grad1 + c1;
printf("%.16Lf %.16Lf",x_meet,y_meet);
}
return 0;
}
printf("0");
} 이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.