题目连接:
http://acm.hdu.edu.cn/showproblem.php?pid=1147
题目意思:
n条线段,先扔的可能被后扔的覆盖掉,求在最顶端没有被覆盖的条,并输出,1<=n<=100,000 最多条数为 p<=1000
题目分析:
对n条暴力的话,准超时,但是注意到p是1000,因此就需要考虑到p。
判断线段相加,假设一个点在线段的左边,则点与线段的叉积为负,如果存在一条线段跨越这条线段,则与这点对应的点在线段的右边,它的叉积为正,这两个叉积相乘为负。但是,注意的是,要以这两条线段分别为基线段,乘积同时都要小于0才能说明相交。
解决TLE核心部分:
肯定会拿n条线段一次搜索,与之比较的是那些没有被覆盖的线段,对于每一个i线段,与未被覆盖的线段(用一个数组保存着)比较,相交了,则不管这条线段了,不相交,则继续保存。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n;
struct line
{
int judge;
double x1,y1,x2,y2;
}L[100000+5];
line f[100000+5];
double xmult(double x1,double y1,double x2,double y2)
{
return x1*y2-x2*y1;
}
int cross(line l1,line l2)
{//一左一右,相乘为负
double a = xmult( (l1.x1-l2.x1),(l1.y1-l2.y1),(l1.x2-l2.x1),(l1.y2-l2.y1) );
double b = xmult( (l1.x1-l2.x2),(l1.y1-l2.y2),(l1.x2-l2.x2),(l1.y2-l2.y2) );
double c = xmult( (l2.x1-l1.x1),(l2.y1-l1.y1),(l2.x2-l1.x1),(l2.y2-l1.y1) );
double d = xmult( (l2.x1-l1.x2),(l2.y1-l1.y2),(l2.x2-l1.x2),(l2.y2-l1.y2) );
return (a*b<=0 && c*d<=0)?1:0;
}
int main()
{
int i,j;
while(scanf("%d",&n),n)
{
int sum=0;
for(i=0;i<n;i++)
{
scanf("%lf%lf%lf%lf",&L[i].x1,&L[i].y1,&L[i].x2,&L[i].y2);
L[i].judge=i+1;
}
for(i=0;i<n;i++)
{
int p=0;
for(j=0;j<sum;j++)
{
if( !cross( L[i],f[j] ) ){//没有相交,说明没有被覆盖掉,继续放置在数组里,否则不操作,即不放进数组里
f[p++] = f[j];
}
}
f[p++] = L[i];
sum = p;
}
printf("Top sticks: %d",f[0].judge);
for(i=1;i<sum;i++)
{
printf(", %d",f[i].judge);
}
printf(".\n");
}
return 0;
}