A - POJ 2318 TOYS
思路:
利用叉积运算,判断点在直线的哪一侧,对于直线 AB 点 O ,如果 向量
OA→×OB→>0 则说明 O 在直线的左侧,以AB→ 的方向作为界定。
所以对于每一个点,二分的找到所在的直线就行了!
代码:
#include <cstdio>
#include <algorithm>
#include <cstring>
#define S first
#define E second
using namespace std;
const int N = 5e3 + 10;
struct Point
{
int x, y;
Point(int x = 0, int y = 0) :x(x), y(y){}
Point operator - (const Point& p)
{
return Point(x - p.x, y - p.y);
}
int operator ^ (const Point& p)
{
return (x * p.y - y * p.x);
}
};
Point UL, LR;
int n, m, ans[N];
pair<Point, Point> L[N];
Point a[N];
// 叉积判断
bool check(Point& S, Point& E, Point p)
{
return ((S - p) ^ (E - p)) > 0;
}
int main()
{
//freopen("in.txt", "r", stdin);
bool fg = 0;
while(scanf("%d", &n), n)
{
scanf("%d%d%d%d%d", &m, &UL.x, &UL.y, &LR.x, &LR.y);
int x, y;
for(int i = 0;i < n;i ++) {
scanf("%d%d", &x, &y);
L[i].S = Point(x, UL.y);
L[i].E = Point(y, LR.y);
}
L[n].S = Point(LR.x, UL.y), L[n].E = LR;
memset(ans, 0, sizeof(ans));
for(int i = 0;i < m;i ++) {
scanf("%d%d", &x, &y);
int l = 0, r = n;
while(l <= r) {
int mid = (l + r) >> 1;
if(check(L[mid].S, L[mid].E, Point(x, y))) l = mid + 1;
else r = mid - 1;
}
ans[l] ++;
}
if(fg) puts("");
for(int i = 0;i <= n;i ++) printf("%d: %d\n", i, ans[i]);
fg = 1;
}
return 0;
}
POJ 2398 Toy Storage
思路:
题意和上个题目一样,但是这个题给定的线段的顺序不一致,所以要把线段从左往右排一遍序,然后解法就和上一题一样了!
POJ 3304 Segments
思路:
首先,可以注意到,如果存在这样的一条穿过所有线段的直线,那么我们可以通过旋转直线使得这条满足条件的直线可以会通过两个端点!
知道这个后,我们就可以枚举两个端点,去确定一条直线,然后判断这条直线是否满足要求,就是判断直线是否与线段相交,具体就是判断是否满足Cross(A,B,o1)∗Cross(A,B,o2)≤0
这题一个比较坑的地方就是:注意判断枚举的两个点不能重合!因为如果两个点重合了的话,那么对于所有的线段都满足相交的条件了。
代码:
#include <cstdio>
#include <algorithm>
#include <cmath>
#define S first
#define E second
#define eps 1e-8
using namespace std;
const int N = 1e2 + 10;
typedef double TP;
struct Point
{
TP x, y;
Point(TP x = 0, TP y = 0) :x(x), y(y){}
Point operator - (const Point& p)
{
return Point(x - p.x, y - p.y);
}
TP operator ^ (const Point& p)
{
return (x * p.y - y * p.x);
}
};
struct Line
{
Point S, E;
Line(Point _s = Point(), Point _e = Point()): S(_s), E(_e) {}
};
Line L[N];
int n;
int dcmp(double x) //
{
if(fabs(x) < eps) return 0;
else return x < 0 ? -1 : 1;
}
bool isok(Point a, Point b)
{
Point x = a - b;
if(dcmp(x.x) == 0 && dcmp(x.y) == 0) return 0;
for(int i = 0;i < n;i ++)
if(dcmp((a - L[i].S) ^ (b - L[i].S)) * dcmp((a - L[i].E) ^ (b - L[i].E)) > 0) return 0;
return 1;
}
int main()
{
freopen("in.txt", "r", stdin);
int T;
scanf("%d", &T);
while(T --)
{
scanf("%d", &n);
for(int i = 0;i < n;i ++) {
scanf("%lf %lf %lf %lf", &L[i].S.x, &L[i].S.y, &L[i].E.x, &L[i].E.y);
}
if(n == 1) {
puts("Yes!");
continue;
}
bool ok = 0;
for(int i = 0;i < n;i ++) {
for(int j = i + 1;j < n;j ++) {
if(isok(L[i].S, L[j].S)
|| isok(L[i].S, L[j].E)
|| isok(L[i].E, L[j].S)
|| isok(L[i].E, L[j].E)) {
ok = 1;
break;
}
}
if(ok) break;
}
puts(ok ? "Yes!": "No!");
}
return 0;
}
POJ 1269 Intersecting Lines
题意:
判断两条直线的位置关系,如果相交,输出交点!
主要是贴个模板。
代码:
#include <cstdio>
#include <algorithm>
#include <cmath>
#define S first
#define E second
#define eps 1e-8
using namespace std;
const int N = 1e2 + 10;
typedef double TP;
struct Point
{
TP x, y;
Point(TP x = 0, TP y = 0) :x(x), y(y){}
Point operator - (const Point& p)
{
return Point(x - p.x, y - p.y);
}
TP operator ^ (const Point& p)
{
return (x * p.y - y * p.x);
}
};
struct Line
{
Point S, E;
Line(Point _s = Point(), Point _e = Point()): S(_s), E(_e) {}
};
int dcmp(double x)
{
if(fabs(x) < eps) return 0;
else return x < 0 ? -1 : 1;
}
TP cross(Point& S, Point& E, Point& O)
{
return (S - O) ^ (E - O);
}
TP cross2(Point& S, Point& E, Point& A, Point& B)
{
return (E.x - S.x) * (B.y - A.y) - (B.x - A.x) * (E.y - S.y);
}
bool onLine(Line& a, Line& b)
{
return dcmp(cross(a.S, a.E, b.S)) == 0 && dcmp(cross(a.S, a.E, b.E)) == 0;
}
bool parallel(Line& a, Line& b)
{
return dcmp(cross2(a.S, a.E, b.S, b.E)) == 0;
}
void intersectionPoint(Line a, Line b, Point& ans)
{
TP a1, b1, c1, a2, b2, c2;
a1 = a.S.y - a.E.y;
b1 = a.E.x - a.S.x;
c1 = a.S.x * a.E.y - a.S.y * a.E.x;
a2 = b.S.y - b.E.y;
b2 = b.E.x - b.S.x;
c2 = b.S.x * b.E.y - b.S.y * b.E.x;
ans.x = (c1 * b2 - c2 * b1) / (a2 * b1 - a1 * b2);
ans.y = (a2 * c1 - a1 * c2) / (a1 * b2 - a2 * b1);
}
int main()
{
//freopen("in.txt", "r", stdin);
puts("INTERSECTING LINES OUTPUT");
int T;
scanf("%d", &T);
while(T --)
{
Line a, b;
scanf("%lf %lf %lf %lf", &a.S.x, &a.S.y, &a.E.x, &a.E.y);
scanf("%lf %lf %lf %lf", &b.S.x, &b.S.y, &b.E.x, &b.E.y);
if(onLine(a, b)) puts("LINE");
else if(parallel(a, b)) puts("NONE");
else {
Point ans;
intersectionPoint(a, b, ans);
printf("POINT %.2f %.2f\n", ans.x, ans.y);
}
}
puts("END OF OUTPUT");
return 0;
}
POJ 1556 The Doors
暴力得到所有点之间的距离,然后跑个最短路,数据小,随便搞!
POJ 2653 Pick-up sticks
用一个set去维护还没有被盖住的线段的编号!每次遇到一个新的线段,扫一遍set就好了!
POJ 1066 Treasure Hunt
跟前面的一个题POJ 3304 的思路类似,枚举所有在边界上的点,与终点连一条线,然后看这条线与所有线段的交点,取个最小值!(另:这题数据貌似很水啊!)