Time Limit: 2000MS | Memory Limit: 30000K | |
Total Submissions: 1313 | Accepted: 245 |
Description
Input
Output
Sample Input
3 1.0 10.0 3.0 14.0 0.0 0.0 20.0 20.0 10.0 28.0 2.0 12.0 2 0.0 0.0 1.0 1.0 1.0 1.0 2.15 2.15 2 0.0 0.0 1.0 1.0 1.0 1.0 2.15 2.16 0
Sample Output
2 1 2
Source
/* 呵呵,这题进前20了 13 6262545 bobten2008 732K 141MS C++ 2246B 2009-12-20 14:52:15 很恶心的计算几何问题,核心思想是利用排序将seg按照斜率进行排序,容易错误的地方有四点 1)精度问题,需要加eps修正. 2)输入数据中的每个seg的两个点的顺序不是按照从左到右或者从下到上,因此需要调整seg的 两个端点比如对于线短1 2 3 2,也有可能以3 2 1 2的形式出现,我在这里统一调成从下到上, 从左到右的顺序,这里如果不调整可能会影响后续的工作. 3)排序算法的比较函数,比较复杂,需要考虑竖线(即没有斜率的情况),详见正文里的注释 4)最后顺序扫描排序后的seg时,需要调整当前seg的x2或者y2值,比如对于 [1 2 10 2], [2 2 5 2] [6 2 12 2]这组数据,排序完也是这个顺序,那么第二个seg被包含在第一个 seg里,如果不修正第二个seg的y2坐标,那么在处理第三个seg时,第三个seg肯定不被包含进来,那么 最后答案是2,其实这组数据的答案应该是1.所以在处理完第二个seg后需要将其y2修正为10. 具体怎么修正呢,很简单,只要取y2为当前seg的y2和上一个seg的y2的最大值即可 算法的时间复杂度是O(nlgn) */ #include <iostream> #include <algorithm> #include <cmath> #define EPS 1e-8 #define MAX_N 10005 using namespace std; struct seg { double x1, y1, x2, y2; bool spe; //spe = true表示当前seg与y轴平行,否则不平行,与y轴平行时是没有斜率的 double a, b; }segs[MAX_N]; int n; //比较函数,核心思想是把没有斜率(与y轴平行)的放在有斜率的后面,把斜率小的放在斜率大的前面 //对于具有相同斜率的seg,把与y轴交点低的放在前面 //对于在一条线上的seg,把x坐标(当与y轴平行时比较y坐标)小的放在前面 bool compare(const seg &seg1, const seg &seg2) { //两个seg都没有斜率 if(seg1.spe && seg2.spe) return fabs(seg1.x1 - seg2.x1) < EPS ? seg1.y1 < seg2.y1 + EPS : seg1.x1 < seg2.x2 + EPS; else if(seg1.spe && !seg2.spe) return false; //一个有斜率一个没有斜率,把有斜率的放在前面 else if(!seg1.spe && seg2.spe) return true; else //两个seg都有斜率 { //斜率相等时需要比较与y轴的交点,当焦点也相等时需要比较左端点x值的大小 if(fabs(seg1.a - seg2.a) < EPS) return fabs(seg1.b - seg2.b) < EPS ? seg1.x1 < seg2.x1 + EPS : seg1.b < seg2.b + EPS; else return seg1.a < seg2.a + EPS; } } void swap(double &d1, double &d2) { double temp = d1; d1 = d2; d2 = temp; } //判断两个seg是否相交, type用来区分这个两个seg与y轴的平行情况,type = 0时表示与y轴平行 bool cross(const seg& seg1, const seg &seg2, bool type) { if(!type) return seg2.y1 <= seg1.y2; else return seg2.x1 <= seg1.x2; } int main() { int i; while(scanf("%d", &n) && n != 0) { for(i = 0; i < n; i++) { scanf("%lf%lf%lf%lf", &segs[i].x1, &segs[i].y1, &segs[i].x2, &segs[i].y2); if(segs[i].x1 > segs[i].x2 + EPS) { swap(segs[i].x1, segs[i].x2); swap(segs[i].y1, segs[i].y2);} else if(fabs(segs[i].x1 - segs[i].x2) < EPS && segs[i].y1 > segs[i].y2 + EPS) { swap(segs[i].x1, segs[i].x2); swap(segs[i].y1, segs[i].y2); } segs[i].spe = false; if(fabs(segs[i].x1 - segs[i].x2) < EPS) segs[i].spe = true; else { segs[i].a = (segs[i].y2 - segs[i].y1) / (segs[i].x2 - segs[i].x1); segs[i].b = segs[i].y1 - segs[i].x1 * segs[i].a; } } sort(segs, segs + n, compare); int countv = 1; for(i = 1; i < n; i++) { //当前seg与y轴平行其与上一个seg相交 if(segs[i].spe && segs[i - 1].spe && fabs(segs[i].x1 - segs[i - 1].x1) < EPS && cross(segs[i - 1], segs[i], false)) { //调整当前seg的y2 if(segs[i].y2 < segs[i - 1].y2 + EPS) segs[i].y2 = segs[i - 1].y2; continue; } //当前seg不与y轴平行且与上一个seg相交 if(!segs[i].spe && !segs[i - 1].spe && fabs(segs[i].a - segs[i - 1].a) < EPS && fabs(segs[i].b - segs[i - 1].b) < EPS && cross(segs[i - 1], segs[i], true)) { //调整当前seg的x2 if(segs[i].x2 < segs[i - 1].x2 + EPS) segs[i].x2 = segs[i - 1].x2; continue; } //找到一个新的不可与上一个seg合并的seg则需要为countv的值增加1 countv++; } printf("%d/n", countv); } return 0; }