一、传送门
http://poj.org/problem?id=2653
https://zoj.pintia.cn/problem-sets/91827364500/problems/91827366050
二、算法分析说明与代码编写指导
overlapped 函数:
返回两个区间是否重叠。若不交,返回-1;只重叠与一点(左端区间的右端点与右端区间的左端点重合),返回0;有重叠,返回1。
cross_product:返回两个二维向量的向量积。二维向量的向量积一般定义成标量:
intersected 函数用快速排斥实验和跨立实验判断两条线段是否相交:
题意:依次往地上扔棍子,问哪些棍子在棍子堆的最顶上。
考察任意两根木棍是否有交点即可。
本题中,无论是否将其中一条线段的交点为端点的情况包括在相交的范畴,都不影响 AC。
但是要注意,外层循环变量是递减的,也就是说先考察后面扔到地上的木棍再考察前面的。原因是:每根木棍只会被后面扔在它上面的木棍压住。如果两层循环的循环变量都是递增的,那么之前判定没有与其它木棍相交的木棍一旦被后来的木棍压住,就无法修正判定结果,导致 WA。当然,由于本题数据量较大,这种出错情况会导致输出的在顶上的木棍数量非常多,从而 TLE。
三、AC 代码
POJ 2653:
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
#pragma warning(disable:4996)
using namespace std;
template<class _Ty> struct point {
_Ty x, y; };
struct segment {
point<double> s, t; };
const unsigned nmax = 100001;
unsigned n; segment s[nmax]; bool top; vector<unsigned> v;
//[a1, b1] ∩ [a2, b2]
template<class _Ty> inline int overlapped(_Ty a1, _Ty b1, _Ty a2, _Ty b2) {
if (a1 > b1)swap(a1, b1); if (a2 > b2)swap(a2, b2);
_Ty m1 = (a1 + b1) / 2, m2 = (a2 + b2) / 2;
if (m1 == m2)return b1 - a1 > 0 && b2 - a2 > 0;
if (m1 < m2) {
if (b1 < a2)return -1; if (b1 == a2)return 0;
return 1;
}
if (b2 < a1)return -1; if (b2 == a1)return 0;
return 1;
}
template<class _Ty> inline _Ty cross_product(const _Ty& x1, const _Ty& y1, const _Ty& x2, const _Ty& y2) {
return x1 * y2 - x2 * y1;
}