是一道比较坑的几何题目,题目大意就是给出一些线段,问最少画多少笔可以把他们都连起来。
注意double的误差,还有斜率的判断,有一些线段重叠的也要特殊处理,最后总的变数减去重复的就是答案啦。
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cmath>
using namespace std;
struct segment
{
double x1, y1, x2, y2, k, b;
bool has_k;
}data[10005];
void deal(segment &s)
{
//交换点的时候要注意,我就是这个一直WA的...
if (s.x1 > s.x2 + 1e-8) swap(s.x1, s.x2), swap(s.y1, s.y2);
else if (fabs(s.x1 - s.x2) < 1e-8 && s.y1 > s.y2 + 1e-8) swap(s.x1, s.x2), swap(s.y1, s.y2);
if (fabs(s.x1 - s.x2) <= 1e-8)
{
s.has_k = false;
return;
}
s.has_k = true;
s.k = (s.y1 - s. y2) / (s.x1 - s.x2);
s.b = s.y1 - s.k * s.x1;
return;
}
bool cmp(segment a, segment b)
{
if (!a.has_k && !b.has_k) return fabs(a.x1 - b.x1) < 1e-8 ? a.y1 < b.y1 + 1e-8 : a.x1 < b.x1 + 1e-8;
if (!a.has_k && b.has_k) return true;
if (a.has_k && !b.has_k) return false;
if (fabs(a.k - b.k) > 1e-8) return a.k < b.k;
if (fabs(a.b - b.b) > 1e-8) return a.b < b.b;
return a.x1 < b.x1;
}
int main()
{
int n;
while (scanf("%d", &n) != EOF && n)
{
int i, j, ans = n;
for (i = 0; i < n; ++ i)
{
scanf("%lf%lf%lf%lf", &data[i].x1, &data[i].y1, &data[i].x2, &data[i].y2);
deal(data[i]);
}
sort(data, data + n, cmp);//点的排序有利于去除有重合的边
for (i = 0; i < n - 1; ++ i)
{
segment &a = data[i];
segment &b = data[i + 1];
if (!a.has_k && !b.has_k && fabs(a.x1 - b.x1) < 1e-8 && b.y1 <= a.y2 + 1e-8)
{
b.y2 = b.y2 < a.y2 + 1e-8 ? a.y2 : b.y2;
ans --;
}
if (a.has_k && b.has_k && fabs(a.k - b.k) < 1e-8 && fabs(a.b - b.b) < 1e-8 && b.x1 <= a.x2 + 1e-8)
{
b.x2 = b.x2 < a.x2 + 1e-8 ? a.x2 : b.x2;
ans --;
}
}
printf("%d\n", ans);
}
return 0;
}