http://poj.org/problem?id=1066
在下图中,
求解从四边到中间终点至少要穿过几堵墙。
浮点数据的线段判断是否相交。另外,我们需要设置四边的起点,不是直接遍历每个坐标,而是找已有的交点。(有一种贪心的意思)。
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const double eps=1e-6;
struct point {
double x,y;
};
struct edge{
point u,v;
}eg[40];
double min(double q1,double q2){
return q1-q2<eps?q1:q2;
}
double max(double q1,double q2){
return q1-q2>eps?q1:q2;
}
bool on(point a,point b,point c){
if(c.x>=min(a.x,b.x)&&c.x<=max(a.x,b.x)&&c.y>=min(a.y,b.y)&&c.y<=max(a.y,b.y))
return 1;
return 0;
}
double multi(point p0,point p1,point p2){
return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
bool cross(point p1,point p2,point p3,point p4){
bool tag=0;
double r1=multi(p3,p4,p1),r2=multi(p3,p4,p2);
double r3=multi(p1,p2,p3),r4=multi(p1,p2,p4);
if(r1*r2<eps&&r3*r4<eps) tag=1;
else if(fabs(r1)<eps&&on(p3,p4,p1))tag=1;
else if(fabs(r2)<eps&&on(p3,p4,p2))tag=1;
else if(fabs(r3)<eps&&on(p1,p2,p3))tag=1;
else if(fabs(r4)<eps&&on(p1,p2,p4)) tag=1;
return tag;
}
int main()
{
//freopen("cin.txt","r",stdin);
int n;
while(cin>>n){
point u,v;
for(int i=0;i<n;i++) {
scanf("%lf%lf%lf%lf",&eg[i].u.x,&eg[i].u.y,&eg[i].v.x,&eg[i].v.y);
}
scanf("%lf%lf",&eg[n].u.x,&eg[n].u.y);
if(n==0){
puts("Number of doors = 1");
continue;
}
int ans=n;
for(int i=0;i<n;i++){ //就选择交点作为另一个端点
eg[n].v.x=eg[i].u.x;
eg[n].v.y=eg[i].u.y;
int sum=0;
for(int j=0;j<n;j++){
if(cross(eg[n].u,eg[n].v,eg[j].u,eg[j].v)) sum++;
}
ans=ans<sum?ans:sum;
eg[n].v.x=eg[i].v.x;
eg[n].v.y=eg[i].v.y;
sum=0;
for(int j=0;j<n;j++){
if(cross(eg[n].u,eg[n].v,eg[j].u,eg[j].v)) sum++;
}
ans=ans<sum?ans:sum;
}
printf("Number of doors = %d\n",ans);
}
return 0;
}
事实上,他还能代码优化:
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const double eps=1e-6;
struct point {
double x,y;
};
struct edge{
point u,v;
}eg[40];
double multi(point p0,point p1,point p2){
return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
bool cross(point p1,point p2,point p3,point p4){
bool tag=0;
double r1=multi(p3,p4,p1),r2=multi(p3,p4,p2);
double r3=multi(p1,p2,p3),r4=multi(p1,p2,p4);
if(r1*r2<eps&&r3*r4<eps) tag=1; //如果是端点接触相交 r1*r2趋近于0 tag=1
return tag;
}
int main()
{
//freopen("cin.txt","r",stdin);
int n;
while(cin>>n){
point u,v;
for(int i=0;i<n;i++) {
scanf("%lf%lf%lf%lf",&eg[i].u.x,&eg[i].u.y,&eg[i].v.x,&eg[i].v.y);
}
scanf("%lf%lf",&eg[n].u.x,&eg[n].u.y);
if(n==0){
puts("Number of doors = 1");
continue;
}
int ans=n;
for(int i=0;i<n;i++){ //就选择交点作为另一个端点
eg[n].v.x=eg[i].u.x;
eg[n].v.y=eg[i].u.y;
int sum=0;
for(int j=0;j<n;j++){
if(cross(eg[n].u,eg[n].v,eg[j].u,eg[j].v)) sum++;
}
ans=ans<sum?ans:sum;
eg[n].v.x=eg[i].v.x;
eg[n].v.y=eg[i].v.y;
sum=0;
for(int j=0;j<n;j++){
if(cross(eg[n].u,eg[n].v,eg[j].u,eg[j].v)) sum++;
}
ans=ans<sum?ans:sum;
}
printf("Number of doors = %d\n",ans);
}
return 0;
}