题目大意:给出火柴(线段)的起点终点,有童鞋无聊按输入顺序扔火柴,求最后所有没有被其他火柴压住的火柴序号。
解题策略:第一反应想到的算法很简单:
1,火柴只能被后来的火柴可能压住 <=> 火柴只能和后来的火柴“相交” ,之前的火柴不考虑;
2,“相交” <=> "规范相交",这里是关键;(详见下图)
3,查找的时候可以优化,提升效率,第一时间想的算法过掉了;
附:
非规范相交:
规范相交:
/*
UVA 10902 POJ 2653 Pick-up sticks
AC by J_Dark
ON 2013/5/3 0:00
Time 0.0.345s
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <climits>
#include <vector>
#include <algorithm>
using namespace std;
///
struct point{
double x, y;
point(double p=0, double q=0){
x = p;
y = q;
}
};
struct line{
point a, b;
line(point x, point y){
a = x;
b = y;
}
};
int segNum;
vector<line> Seg;
vector<int> topSeg;
///
void Input(){
Seg.clear();
topSeg.clear();
double ax, ay, bx, by;
for(int i=0; i<segNum; i++){
cin >> ax >> ay >> bx >> by;
point start(ax, ay), end(bx, by);
Seg.push_back(line(start, end));
}
}
double Direction(point Pi, point Pj, point Pk){
return (Pj.x-Pi.x)*(Pk.y-Pi.y)-(Pk.x-Pi.x)*(Pj.y-Pi.y);
}
bool isIntersect(line p, line q){
double d1, d2, d3, d4;
d1 = Direction(p.a, p.b, q.a);
d2 = Direction(p.a, p.b, q.b);
d3 = Direction(q.a, q.b, p.a);
d4 = Direction(q.a, q.b, p.b);
if(d1*d2<0 && d3*d4<0) { return true;} //规范相交
//非规范相交
else return false;
}
void Compute(){
bool ff;
//这里可以优化,大大提高效率
for(int i=0; i<segNum; i++){
ff = false;
for(int k=i+1; k<segNum; k++){
if( isIntersect(Seg[i], Seg[k]) ){
ff = true;
break;
}
}
if(!ff) topSeg.push_back(i+1);
}
}
void Output(){
cout << "Top sticks: ";
for(int i=0; i<topSeg.size(); i++){
if(i>0) cout << ", " << topSeg[i];
else cout << topSeg[i];
}
cout << "." << endl;
}
///
int main(){
while(cin >> segNum && segNum)
{
Input();
Compute();
Output();
}
return 0;
}