目录
直线
力扣 149. 直线上最多的点数
给你一个数组 points
,其中 points[i] = [xi, yi]
表示 X-Y 平面上的一个点。求最多有多少个点在同一条直线上。
示例 1:
输入:points = [[1,1],[2,2],[3,3]] 输出:3
示例 2:
输入:points = [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]] 输出:4
提示:
1 <= points.length <= 300
points[i].length == 2
-104 <= xi, yi <= 104
points
中的所有点 互不相同
class Solution {
public:
int maxPoints(vector<vector<int>>& points) {
map<vector<int>, int>m;
for (int i = 0; i < points.size(); i++)for (int j = i + 1; j < points.size(); j++) {
m[getPair(points[i], points[j])]++;
}
int ans = 0;
for (auto it : m)ans = max(ans, it.second);
return int(sqrt(ans * 2 + 1.0 / 4)) + 1;
}
vector<int> getPair(vector<int> a, vector<int> b) {
int x = a[1] - b[1], y = a[0] - b[0];
int g = Gcd(x, y);
return vector<int>{x / g, y / g, y / g * a[1] - x / g * a[0]};
}
};
CSU 1407 最短距离
题目:
Description
两个点 A , B 均在做匀速直线运动。给出 t = 0时刻 A , B 的坐标,以及 A , B 的速度,计算 t ≥ 0时两个点的距离的最小值。
Input
输入的第一行包含一个整数 T (1 ≤ T ≤ 200 ),表示一共有 T 组测试数据。
对于每组测试数据,第一行包含4个整数 x A , y A , v Ax , v Ay (-10 3 ≤ x A , y A , v Ax , v Ay ≤ 10 3 ),表示 t = 0时刻 A 的坐标为( x A , y A ), A 的速度在 x 轴方向上的分量为 v Ax ,在 y 轴上的分量为 v Ay 。第二行包含四个整数 x B , y B , v Bx , v By (-10 3 ≤ x B , y B , v Bx , v By ≤ 10 3 ),以相同的方式给出了 B 的各项属性。
Output
对于每组测试数据,输出 t ≥ 0时两个点距离的最小值,保留8位小数。
Sample Input
6
0 0 0 0
0 1 0 1
0 0 -1 1
0 0 1 -1
0 1 1 0
2 0 0 1
0 1 1 0
2 0 1 0
0 0 -1 1
1 1 1 -1
997 997 -1000 -1000
-1000 -1000 1000 1000
Sample Output
1.00000000
0.00000000
0.70710678
2.23606798
1.41421356
0.00000000
代码:
#include<iostream>
#include<math.h>
#include<iomanip>
using namespace std;
int main()
{
int t;
double xa, ya, vxa, vya;
double xb, yb, vxb, vyb;
double a, b, c;//att+2bt+c
cin >> t;
while (t--)
{
cin >> xa >> ya >> vxa >> vya;
cin >> xb >> yb >> vxb >> vyb;
a = (vxa - vxb)*(vxa - vxb) + (vya - vyb)*(vya - vyb);
b = (vxa - vxb)*(xa - xb) + (vya - vyb)*(ya - yb);
c = (xa - xb)*(xa - xb) + (ya - yb)*(ya - yb);
cout << setprecision(10) << sqrt((a*b >= 0) ? c : c - b * b / a) << endl;
}
return 0;
}
力扣 面试题 16.03. 交点
给定两条线段(表示为起点start = {X1, Y1}
和终点end = {X2, Y2}
),如果它们有交点,请计算其交点,没有交点则返回空值。
要求浮点型误差不超过10^-6
。若有多个交点(线段重叠)则返回 X 值最小的点,X 坐标相同则返回 Y 值最小的点。
示例 1:
输入: line1 = {0, 0}, {1, 0} line2 = {1, 1}, {0, -1} 输出: {0.5, 0}
示例 2:
输入: line1 = {0, 0}, {3, 3} line2 = {1, 1}, {2, 2} 输出: {1, 1}
示例 3:
输入: line1 = {0, 0}, {1, 1} line2 = {1, 0}, {2, 1} 输出: {},两条线段没有交点
提示:
- 坐标绝对值不会超过 2^7
- 输入的坐标均是有效的二维坐标
class Solution {
public:
vector<double> intersection(vector<int>& start1, vector<int>& end1, vector<int>& start2, vector<int>& end2) {
Line line1(Point{ start1[0],start1[1] }, Point{ end1[0],end1[1] });
Line line2(Point{ start2[0],start2[1] }, Point{ end2[0],end2[1] });
if (IsSameLine(line1, line2)) {
if (PointInSegment(Point{ start1[0],start1[1] }, Point{ end1[0],end1[1] }, Point{ start2[0],start2[1] })) {
return vector<double>{double(start2[0]), double(start2[1])};
}
if (PointInSegment(Point{ start2[0],start2[1] }, Point{ end2[0],end2[1] }, Point{ start1[0],start1[1] })) {
return vector<double>{double(start1[0]), double(start1[1])};
}
return vector<double>{};
}
if (IsParallels(line1, line2)) {
return vector<double>{};
}
Point p = IntersectionLineAndLine(line1, line2);
if (PointInSegment(Point{ start1[0],start1[1] }, Point{ end1[0],end1[1] }, p)
&& PointInSegment(Point{ start2[0],start2[1] }, Point{ end2[0],end2[1] }, p)) {
return vector<double>{p.x, p.y};
}
return vector<double>{};
}
};
力扣 LCP 37. 最小矩形面积
二维平面上有 𝑁N 条直线,形式为 y = kx + b
,其中 k
、b
为整数 且 k > 0
。所有直线以 [k,b]
的形式存于二维数组 lines
中,不存在重合的两条直线。两两直线之间可能存在一个交点,最多会有 𝐶𝑁2CN2 个交点。我们用一个平行于坐标轴的矩形覆盖所有的交点,请问这个矩形最小面积是多少。若直线之间无交点、仅有一个交点或所有交点均在同一条平行坐标轴的直线上,则返回0。
注意:返回结果是浮点数,与标准答案 绝对误差或相对误差 在 10^-4 以内的结果都被视为正确结果
示例 1:
输入:
lines = [[2,3],[3,0],[4,1]]
输出:
48.00000
解释:三条直线的三个交点为 (3, 9) (1, 5) 和 (-1, -3)。最小覆盖矩形左下角为 (-1, -3) 右上角为 (3,9),面积为 48
示例 2:
输入:
lines = [[1,1],[2,3]]
输出:
0.00000
解释:仅有一个交点 (-2,-1)
限制:
1 <= lines.length <= 10^5 且 lines[i].length == 2
1 <= lines[0] <= 10000
-10000 <= lines[1] <= 10000
与标准答案绝对误差或相对误差在 10^-4 以内的结果都被视为正确结果
class Solution {
public:
double minRecSize(vector<vector<int>>& lines) {
vector<Point>v;
for (auto vi : lines)v.push_back(Point(vi[0], vi[1]));
double xmax = GetMaxSlope(v);
double xmin = GetMinSlope(v);
if (xmax == xmin || xmax==-DBL_MAX)return 0;
v.clear();
for (auto vi : lines)v.push_back(Point(1.0/vi[0], vi[1]*1.0/vi[0]));
double ymax = GetMaxSlope(v);
double ymin = GetMinSlope(v);
if (ymax == ymin || ymax==-DBL_MAX)return 0;
return (xmax - xmin)*(ymax - ymin);
}
};
三角形
CSU 1201 Triangle
题目:
Description
已知三角形各边边长的取值范围,你能求出三角形最大的面积吗?
Input
输入数据的第一行包含一个整数T (1 <= T <= 200),表示接下来一共有T组测试数据。
每组数据占三行,每行均包含两个整数x, y (1 <= x <= y <= 1000),表示该边边长可以为[x, y]范围内的任意实数。
Output
用一行输出三角形的最大的面积,结果保留3位小数。如果三条边不能构成三角形,则用一行输出“No Triangle”(不包括引号)。
Sample Input
2
1 2
1 2
4 5
1 3
2 3
3 3
Sample Output
No Triangle
3.897
代码:
#include<iostream>
#include<stdio.h>
#include<math.h>
using namespace std;
struct node
{
int x, y;
}nod[3];
double g(double a, double b, double c)
{
double p = (a + b + c) / 2;
return sqrt(p*(p - a)*(p - b)*(p - c));
}
double f(double a, int b, int x, int y)
{
if (x >= a + b) return -1;
double s = sqrt(a*a + b*b);
if (x > s)return g(a, b, x);
if (y < s)return g(a, b, y);
return a*b / 2;
}
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
scanf("%d%d%d%d%d%d", &nod[0].x, &nod[0].y, &nod[1].x, &nod[1].y, &nod[2].x, &nod[2].y);
int i1 = 0, i2 = 1, i3 = 2;
if (nod[i1].y > nod[i2].y)i1 ^= i2 ^= i1 ^= i2;
if (nod[i1].y > nod[i3].y)i1 ^= i3 ^= i1 ^= i3;
if (nod[i2].y > nod[i3].y)i2 ^= i3 ^= i2 ^= i3;
double r = f(nod[i1].y, nod[i2].y, nod[i3].x, nod[i3].y);
if (r>-1)printf("%.3f\n", r);
else printf("No Triangle\n");
}
return 0;
}
CSU 1403 三角形面积
题目:
Description
给出三维空间上的三个点,计算以这三个点为顶点的三角形的面积。
Input
输入的第一行包含一个整数T (T > 0),表示一共有T组测试数据。
每组数据占三行,每行各描述了一个点的坐标。点的坐标会以x y z的形式给出,表示这个点的坐标为(x, y, z),其中x, y, z均为[-100, 100]范围内的浮点数。
Output
对于每组测试数据,输出三角形的面积(和标准答案的误差不超过10-6即可)。
Sample Input
2
0 1 0
1 0 0
0 0 0
0 0.0 1.00
1.0 0.00 0
0.00 1.0 0
Sample Output
0.50
0.8660254
代码:
#include<iostream>
#include<math.h>
#include<iomanip>
using namespace std;
int main()
{
int t;
double xa, ya, za, xb, yb, zb, xc, yc, zc;
double l1, l2, l3, p;
cin >> t;
while (t--)
{
cin >> xa >> ya >> za >> xb >> yb >> zb >> xc >> yc >> zc;
l1 = sqrt((xa - xb)*(xa - xb) + (ya - yb)*(ya - yb) + (za - zb)*(za - zb));
l2 = sqrt((xa - xc)*(xa - xc) + (ya - yc)*(ya - yc) + (za - zc)*(za - zc));
l3 = sqrt((xb - xc)*(xb - xc) + (yb - yc)*(yb - yc) + (zb - zc)*(zb - zc));
p = (l1 + l2 + l3) / 2;
cout << setprecision(16) << sqrt(p*(p - l1)*(p - l2)*(p - l3)) << endl;
}
return 0;
}
CSU 1591 三角形
题目:
Description
star有n根火柴棒。由于他的火柴棒不是制式的,所以长度可能会不一样。现在star想选三根火柴棒搭一个三角形送给女朋友,并且希望三角形的面积尽量大。现在希望你编程告诉star可能搭成的最大三角形的面积是多少。
Input
第一行只有一个整数T(1<=T<=20),表示数据组数。
下面的T行每一行有一个整数n(3<=n<=100),表示火柴棒的数量,后面跟着n个整数Li(1<=Li<=100),表示n跟火柴棒的长度。
Output
对于每一组数据输出一个浮点数S,表示最大面积。
结果保留三位小数(四舍五入)。
如果无法搭成三角形,输出”no”。
Sample Input
3
3 3 4 5
4 3 4 5 5
3 1 1 2
Sample Output
6.000
9.165
no
代码:
#include<iostream>
#include<math.h>
#include<stdio.h>
using namespace std;
double f(int a, int b, int c)
{
if (a + b <= c || a + c <= b || b + c <= a)return 0;
double p = (a + b + c)*0.5;
return sqrt(p*(p - a)*(p - b)*(p - c));
}
int main()
{
int t, n, len[100];
cin >> t;
while (t--)
{
cin >> n;
for (int i = 0; i < n; i++)cin >> len[i];
double max = 0;
for (int i = 0; i < n; i++)for (int j = i + 1; j < n; j++)for (int k = j + 1; k < n; k++)
if (max < f(len[i], len[j], len[k]))max = f(len[i], len[j], len[k]);
if (max)printf("%.3f\n", max);
else cout << "no\n";
}
return 0;
}
正方形
力扣 2013. 检测正方形
给你一个在 X-Y 平面上的点构成的数据流。设计一个满足下述要求的算法:
- 添加 一个在数据流中的新点到某个数据结构中。可以添加 重复 的点,并会视作不同的点进行处理。
- 给你一个查询点,请你从数据结构中选出三个点,使这三个点和查询点一同构成一个 面积为正 的 轴对齐正方形 ,统计 满足该要求的方案数目。
轴对齐正方形 是一个正方形,除四条边长度相同外,还满足每条边都与 x-轴 或 y-轴 平行或垂直。
实现 DetectSquares
类:
DetectSquares()
使用空数据结构初始化对象void add(int[] point)
向数据结构添加一个新的点point = [x, y]
int count(int[] point)
统计按上述方式与点point = [x, y]
共同构造 轴对齐正方形 的方案数。
示例:
输入: ["DetectSquares", "add", "add", "add", "count", "count", "add", "count"] [[], [[3, 10]], [[11, 2]], [[3, 2]], [[11, 10]], [[14, 8]], [[11, 2]], [[11, 10]]] 输出: [null, null, null, null, 1, 0, null, 2] 解释: DetectSquares detectSquares = new DetectSquares(); detectSquares.add([3, 10]); detectSquares.add([11, 2]); detectSquares.add([3, 2]); detectSquares.count([11, 10]); // 返回 1 。你可以选择: // - 第一个,第二个,和第三个点 detectSquares.count([14, 8]); // 返回 0 。查询点无法与数据结构中的这些点构成正方形。 detectSquares.add([11, 2]); // 允许添加重复的点。 detectSquares.count([11, 10]); // 返回 2 。你可以选择: // - 第一个,第二个,和第三个点 // - 第一个,第三个,和第四个点
提示:
point.length == 2
0 <= x, y <= 1000
- 调用
add
和count
的 总次数 最多为5000
class DetectSquares {
public:
DetectSquares() {
m.clear();
}
void add(const vector<int> &point) {
m[point]++;
}
int count(vector<int> point) {
int ans = 0;
for (auto &mi : m) {
if (same(mi.first, point))continue;
if(!line(mi.first, point))continue;
if (mi.first[0] == point[0]) {
int len = mi.first[1] - point[1];
auto it1 = m.find(vector<int>{mi.first[0] + len, mi.first[1]});
auto it2= m.find(vector<int>{point[0] + len, point[1]});
if (it1 != m.end() && it2 != m.end()) {
ans += it1->second * it2->second*mi.second;
}
it1 = m.find(vector<int>{mi.first[0] - len, mi.first[1]});
it2 = m.find(vector<int>{point[0] - len, point[1]});
if (it1 != m.end() && it2 != m.end()) {
ans += it1->second * it2->second*mi.second;
}
}
}
return ans;
}
bool same(const vector<int>&v1, const vector<int>&v2) {
return v1[0] == v2[0] && v1[1] == v2[1];
}
bool line(const vector<int>&v1, const vector<int>&v2) {
return v1[0] == v2[0] || v1[1] == v2[1];
}
map<vector<int>, int>m;
};
力扣 面试题 16.13. 平分正方形
给定两个正方形及一个二维平面。请找出将这两个正方形分割成两半的一条直线。假设正方形顶边和底边与 x 轴平行。
每个正方形的数据square
包含3个数值,正方形的左下顶点坐标[X,Y] = [square[0],square[1]]
,以及正方形的边长square[2]
。所求直线穿过两个正方形会形成4个交点,请返回4个交点形成线段的两端点坐标(两个端点即为4个交点中距离最远的2个点,这2个点所连成的线段一定会穿过另外2个交点)。2个端点坐标[X1,Y1]
和[X2,Y2]
的返回格式为{X1,Y1,X2,Y2}
,要求若X1 != X2
,需保证X1 < X2
,否则需保证Y1 <= Y2
。
若同时有多条直线满足要求,则选择斜率最大的一条计算并返回(与Y轴平行的直线视为斜率无穷大)。
示例:
输入: square1 = {-1, -1, 2} square2 = {0, -1, 2} 输出: {-1,0,2,0} 解释: 直线 y = 0 能将两个正方形同时分为等面积的两部分,返回的两线段端点为[-1,0]和[2,0]
提示:
square.length == 3
square[2] > 0
bool cmp(Point p1, Point p2) {
if (p1.x != p2.x)return p1.x < p2.x;
return p1.y < p2.y;
}
class Solution {
public:
vector<double> cutSquares(vector<int>& square1, vector<int>& square2) {
double a = square1[0] + square1[2] / 2.0;
double b = square1[1] + square1[2] / 2.0;
double c = square2[0] + square2[2] / 2.0;
double d = square2[1] + square2[2] / 2.0;
Line s;
if (a == c)s = Line(1, 0, -a);
else s = Line(Point(a, b), Point(c, d));
vector<Point>intersection;
Polygon p1(vector<Point>{Point(square1[0], square1[1]), Point(square1[0], square1[1] + square1[2]),
Point(square1[0] + square1[2], square1[1] + square1[2]), Point(square1[0] + square1[2], square1[1])});
Polygon p2(vector<Point>{Point(square2[0], square2[1]), Point(square2[0], square2[1] + square2[2]),
Point(square2[0] + square2[2], square2[1] + square2[2]), Point(square2[0] + square2[2], square2[1])});
GetPosStatus(p1, s, intersection);
GetPosStatus(p2, s, intersection);
sort(intersection.begin(), intersection.end(), cmp);
Point pt1 = intersection[0];
Point pt2 = intersection[intersection.size()-1];
return vector<double>{pt1.x, pt1.y, pt2.x, pt2.y};
}
};
多边形
CSU 1007 矩形着色
题目:
Description
Danni想为屏幕上的一个矩形着色,但是她想到了一个问题。当点击鼠标以后电脑是如何判断填充的区域呢?现在给你一个平面直角坐标系,其中有一个矩形和一个点,矩形的四条边均是平行于x轴或y轴的。请你判断这个点相对于矩形的位置,即在矩形内,在矩形上,还是在矩形外?
Input
第一行只有一个整数T,(T < 150),代表共有T种情况。
接下对于每种情况,均有两行数据:
第一行有两个整数Px Py,以空格分隔,代表点的坐标(Px,Py).
第二行有四个整数Ax Ay Bx By,以空格分隔,代表矩形左下角的坐标(Ax,Ay)和右上角的坐标(Bx,By).
所有的坐标均为区间[0,100]内的整数,且Ax<Bx,Ay<By
Output
对于每种情况仅输出一行:
1. 如果点在矩形外部,请输出”Outside”
2. 如果点正好在矩形的边上,请输出”On”
3. 如果点在矩形内部,请输出”Inside”
所有输出都不包含引号。
Sample Input
3
38 730 7 52 66
55 1
9 13 54 84
74 67
73 66 76 68
Sample Output
On
Outside
Inside
代码:
#include<iostream>
using namespace std;
int main()
{
int t;
cin >> t;
while (t--)
{
int px, py,ax, ay, bx, by;
cin >> px >> py >> ax >> ay >> bx >> by;
if (px<ax || px>bx || py<ay || py>by)cout << "Outside";
else if (px == ax || px == bx || py == ay || py == by)cout << "On";
else cout << "Inside";
cout << endl;
}
return 0;
}
力扣 469. 凸多边形
给定 X-Y 平面上的一组点 points ,其中 points[i] = [xi, yi] 。这些点按顺序连成一个多边形。
如果该多边形为 凸 多边形(凸多边形的定义)则返回 true ,否则返回 false 。
你可以假设由给定点构成的多边形总是一个 简单的多边形(简单多边形的定义)。换句话说,我们要保证每个顶点处恰好是两条边的汇合点,并且这些边 互不相交 。
示例 1:
输入: points = [[0,0],[0,5],[5,5],[5,0]]
输出: true
示例 2:
输入: points = [[0,0],[0,10],[10,10],[10,0],[5,5]]
输出: false
提示:
3 <= points.length <= 104
points[i].length == 2
-104 <= xi, yi <= 104
所有点都 不同
class Solution {
public:
bool isConvex(vector<vector<int>>& points) {
points.push_back(points[0]);
for (int i = points.size()-1; i; i--)
points[i][0] -= points[i - 1][0], points[i][1] -= points[i - 1][1];
points[0] = points[points.size() - 1];
long long n = 0;
for (int i = 1; i < points.size(); i++) {
int k = points[i][1] * points[i - 1][0] - points[i - 1][1] * points[i][0];
//if (k== 0)return false;
if (n == 0)n = k;
if (n * k < 0)return false;
}
return true;
}
};
CSU 1159 中南才女
Description
话说中南有位才女,叫做珊,学校里面很多同学都很喜欢她,想追她做女朋友。hkx也不例外。可是不知道为什么,向她表白的同学都一一落马,一向自卑的hkx一直也不敢表白,hkx得知珊有一天晚上8点钟以后的某段时间会去学校的某个地方弹吉他,可是hkx晚上9点以后才有时间去,虽然晚了一点,但也有机会,所以hkx就去了。
假设珊晚上到达的时刻是等可能的分布在8点到8+L点,hkx到达的时刻是等可能的分布在9点到9+L点。珊到达之后会在那里弹吉他t小时,之后就会离开。hkx到达之后如果没见到珊的话,他就会等上t小时,如果这t小时内珊还不出现,他就会离开。那么hkx能够见到珊的概率是多少呢?
Input
多组数据,每组数据包括两个实数,L和t,一组数据占一行
1<=L<=10
0<=t<=10
Output
输出hkx能够见到珊的概率,四舍五入到小数点后6位
Sample Input
2.0 0.0
2.0 3.0
Sample Output
0.000000
1.000000
这个题目其实好简单,就是在 1<y<1+L,0<x<L 这个正方形中,求满足 |y-x|<t 的部分所占的比例。
无非就是把直线y=x的下面和上面的部分分开求。
下面的部分是
sum = (l - 1)*(l - 1) / 2;
if (t < l - 1)sum -= (l - 1 - t)*(l - 1 - t) / 2;
上面的部分是
if (t < 1)sum += t*t / 2 + t*(l - 1);
else if(t<l+1)sum += l - 0.5 + l*l / 2 - (l - t + 1)*(l - t + 1) / 2;
else sum += l - 0.5 + l*l / 2;
完整代码:
#include<iostream>
#include<iomanip>
using namespace std;
int main()
{
double t, l, sum;
while(cin >> l >> t)
{
sum = (l - 1)*(l - 1) / 2;
if (t < l - 1)sum -= (l - 1 - t)*(l - 1 - t) / 2;
if (t < 1)sum += t*t / 2 + t*(l - 1);
else if(t<l+1)sum += l - 0.5 + l*l / 2 - (l - t + 1)*(l - t + 1) / 2;
else sum += l - 0.5 + l*l / 2;
cout << fixed << setprecision(6) << sum / l / l << endl;
}
return 0;
}
CSU 1204 Rectangles
题目:
Description
如果限定矩形的边长必须为整数,且周长为定值L,那么面积在[A, B]范围内不同的矩形一共有多少个呢?
在这个问题中,当且仅当两个矩形面积不同时,视作是两个不同的矩形。
Input
输入数据的第一行包含一个整数T (1 <= T <= 10000),表示接下来一共有T组测试数据。
对于每组测试数据,包含三个整数L (1 <= L <= 2,000,000,000)、A、B (1 <= A <= B <= 250,000,000,000,000,000),含义同上。
Output
对于每组测试数据,用一行输出一个整数,代表上述问题的答案。
Sample Input
3
11 1 6
12 5 10
12 8 10
Sample Output
0
3
2
这个题目,很明显是必须直接求出表达式,因为给的数太大了。
代码:
#include<iostream>
#include<math.h>
using namespace std;
int main()
{
int T;
cin >> T;
long long a, b, l, max, min;
while (T--)
{
cin >> l >> a >> b;
if (l % 2)cout << 0 << endl;
else
{
l = l / 2;
max = l / 2;
if (max*(l - max) > b)
{
max = (long long)(l*1.0 / 2 - sqrt(l*l*1.0 / 4 - b));
if (max*(l - max) > b)max -= 1;
else if ((max + 1)*(l - max - 1) <= b && max < l / 2)max += 1;
}
min = (l + 1) / 2;
if (min*(l - min) == a)
{
cout << 1 << endl;
continue;
}
if (min*(l - min) < a)
{
cout << 0 << endl;
continue;
}
else
{
min = (long long)(l*1.0 / 2 - sqrt(l*l*1.0 / 4 - a)) + 1;
if ((min - 1)*(l - min + 1) >= a)min -= 1;
else if (min*(l - min)<a)min += 1;
}
if (max && min <= max)cout << max - min + 1 << endl;
else cout << 0 << endl;
}
}
return 0;
}
POJ 2002 Squares
题目:
A square is a 4-sided polygon whose sides have equal length and adjacent sides form 90-degree angles. It is also a polygon such that rotating about its centre by 90 degrees gives the same polygon. It is not the only polygon with the latter property, however, as a regular octagon also has this property.
So we all know what a square looks like, but can we find all possible squares that can be formed from a set of stars in a night sky? To make the problem easier, we will assume that the night sky is a 2-dimensional plane, and each star is specified by its x and y coordinates.
Input
The input consists of a number of test cases. Each test case starts with the integer n (1 <= n <= 1000) indicating the number of points to follow. Each of the next n lines specify the x and y coordinates (two integers) of each point. You may assume that the points are distinct and the magnitudes of the coordinates are less than 20000. The input is terminated when n = 0.
Output
For each test case, print on a line the number of squares one can form from the given stars.
Sample Input
4
1 0
0 1
1 1
0 0
9
0 0
1 0
2 0
0 2
1 2
2 2
0 1
1 1
2 1
4
-2 5
3 7
0 0
5 2
0
Sample Output
1
6
1
题意:给出n个点,求出正方形数量
超时代码:
#include<iostream>
#include<algorithm>
#include<cmath>
#include<string.h>
using namespace std;
struct node
{
long long sum, dx, dy;
};
long long point[1000];
long long h = 40001;
node nod[1000000];
bool cmp(node a, node b)
{
return a.sum < b.sum;
}
long long getx(long long m)
{
if (m >= 0)return m / h;
else return (m + 1) / h - 1;
}
long long f(long long a, long long b) //屏蔽掉对称性
{
if (a > b)return a*h + b;
return a + b*h;
}
int main()
{
ios_base::sync_with_stdio(false);
int n, x, y;
while (cin >> n)
{
if (n == 0)break;
for (int i = 0; i < n; i++)
{
cin >> x >> y;
point[i] = x*h + y + h / 2; //y + h / 2是0到4万, x*h + y + h / 2是大约-8亿到8亿
}
for (int i = 0; i < n*n; i++)
{
nod[i].sum = h *h * 2000000000;
nod[i].dx = 0;
nod[i].dy = 0;
}
for (int i = 0; i < n; i++)for (int j = i + 1; j < n; j++)
{
nod[i*n + j].dx = getx(point[i]) - getx(point[j]);
nod[i*n + j].dy = point[i] - getx(point[i])*h - (point[j] - getx(point[j])*h);
nod[i*n + j].sum = (point[i] + point[j])*h*h + f(abs(int(nod[i*n + j].dx)), abs(int(nod[i*n + j].dy)));//屏蔽掉正负
}
sort(nod, nod + n*n, cmp);
int j, num = 0;
for (int i = 1; i <= n*n; i++)
{
if (nod[i].sum == h *h * 2000000000)break;
if (nod[i].sum == nod[i - 1].sum) //满足这个的最多只有8种情况
{
j = i - 1;
while (i <= n*n && nod[i].sum == nod[i - 1].sum)
{
for (int k = j; k < i; k++)
{
if (nod[k].dx == nod[i].dy && nod[k].dy == -nod[i].dx)num++;
if (nod[k].dy == nod[i].dx && nod[k].dx == -nod[i].dy)num++;
}
i++;
}
}
}
cout << num << endl;
}
return 0;
}
正确思路:枚举每2个点组成的线段,判断是不是正方形的对角线
代码:
#include<iostream>
#include<map>
using namespace std;
int N = 50000;
struct node
{
int dx;
int dy;
}nod[1005];
map<int,int>m;
int main()
{
ios_base::sync_with_stdio(false);
int n, x, y;
while (cin >> n)
{
m.clear();
if (n == 0)break;
for (int i = 0; i < n; i++)
{
cin >> nod[i].dx >> nod[i].dy;
m.insert(pair<int,int>(nod[i].dx*N+nod[i].dy,1));
}
int sum = 0;
for (int i = 0; i < n; i++)for (int j = i+1; j < n; j++)
{
x = nod[i].dx + nod[j].dx + nod[i].dy - nod[j].dy;
y = nod[i].dy + nod[j].dy + nod[j].dx - nod[i].dx;
if (x % 2 || y % 2)continue;
x /= 2, y /= 2;
if (x > 20000 || x < -20000 || y>20000 || y < -20000)continue;
if (m.find(x*N + y) == m.end())continue;
x = nod[i].dx + nod[j].dx + nod[j].dy - nod[i].dy;
y = nod[i].dy + nod[j].dy + nod[i].dx - nod[j].dx;
if (x % 2 || y % 2)continue;
x /= 2, y /= 2;
if (x > 20000 || x < -20000 || y>20000 || y < -20000)continue;
if (m.find(x*N + y) == m.end())continue;
sum++;
}
cout << sum/2 << endl;
}
return 0;
}
圆
CSU 1011 Counting Pixels
题目:
Description
Did you know that if you draw a circle that fills the screen on your 1080p high definition display, almost a million pixels are lit? That's a lot of pixels! But do you know exactly how many pixels are lit? Let's find out!
Assume that our display is set on a Cartesian grid where every pixel is a perfect unit square. For example, one pixel occupies the area of a square with corners (0,0) and (1,1). A circle can be drawn by specifying its center in grid coordinates and its radius. On our display, a pixel is lit if any part of it is covered by the circle being drawn; pixels whose edge or corner are just touched by the circle, however, are not lit.
Your job is to compute the exact number of pixels that are lit when a circle with a given position and radius is drawn.
Input
The input consists of several test cases, each on a separate line. Each test case consists of three integers, x,y, and r(1≤x,y,r≤1,000,000), specifying respectively the center (x,y) and radius of the circle drawn. Input is followed by a single line with x = y = r = 0, which should not be processed.
Output
For each test case, output on a single line the number of pixels that are lit when the specified circle is drawn. Assume that the entire circle will fit within the area of the display.
Sample Input
1 1 1
5 2 5
0 0 0
Sample Output
4
88
思路:
x和y是没用的,直接暴力求解加起来就行
代码:
#include<iostream>
#include<math.h>
using namespace std;
int main()
{
long long r, ans;
while (cin >> r >> r >> r)
{
if (r == 0)break;
ans = 0;
for (long long i = 0; i < r; i++)
ans += int(sqrt(r*r - i * i) - 0.000000001) + 1;
cout << ans * 4 << endl;
}
return 0;
}
力扣 1401. 圆和矩形是否有重叠
给你一个以 (radius, xCenter, yCenter) 表示的圆和一个与坐标轴平行的矩形 (x1, y1, x2, y2) ,其中 (x1, y1) 是矩形左下角的坐标,而 (x2, y2) 是右上角的坐标。
如果圆和矩形有重叠的部分,请你返回 true ,否则返回 false 。
换句话说,请你检测是否 存在 点 (xi, yi) ,它既在圆上也在矩形上(两者都包括点落在边界上的情况)。
示例 1 :
输入:radius = 1, xCenter = 0, yCenter = 0, x1 = 1, y1 = -1, x2 = 3, y2 = 1
输出:true
解释:圆和矩形存在公共点 (1,0) 。
示例 2 :
输入:radius = 1, xCenter = 1, yCenter = 1, x1 = 1, y1 = -3, x2 = 2, y2 = -1
输出:false
示例 3 :
输入:radius = 1, xCenter = 0, yCenter = 0, x1 = -1, y1 = 0, x2 = 0, y2 = 1
输出:true
提示:
1 <= radius <= 2000
-104 <= xCenter, yCenter <= 104
-104 <= x1 < x2 <= 104
-104 <= y1 < y2 <= 104
class Solution {
public:
bool checkOverlap(double r, double xCenter, double yCenter, double x1, double y1, double x2, double y2) {
if(xCenter>=x1-r&&xCenter<=x2+r&&yCenter>=y1&&yCenter<=y2)return true;
if(xCenter>=x1&&xCenter<=x2&&yCenter>=y1-r&&yCenter<=y2+r)return true;
Point O{xCenter, yCenter};
return InCircle(O,r,Point{x1,y1})||InCircle(O,r,Point{x1,y2})||InCircle(O,r,Point{x2,y1})||InCircle(O,r,Point{x2,y2});
}
};
凸包
凸包是算法很多,思路也很直白。我找了下和我思路一样的算法,应该是叫Andrew。
我的思路就是上凸包和下凸包分开求,二者类似。
以下凸包为例,起点是左下(最左边的点,如果有多个,那么取其中最下面的),终点是右下。
求取方法是从左往右依次输入所有点,按照斜率不断刷新下凸包点集。
我还给出了根据上凸包求y-kx最大值,或根据下凸包求y-kx最小值的程序。
struct Point
{
double x;
double y;
bool operator<(const Point &p)const
{
if (x == p.x)return y < p.y;
return x < p.x;
}
};
class GeometryBase {
public:
static double slope(Point p1, Point p2)//x一定不同
{
return (p2.y - p1.y) / (p2.x - p1.x);
}
static bool less(double x, double x2) {
return x < x2;
}
static bool lesseq(double x, double x2) {
return x <= x2;
}
};
class Andrew:public GeometryBase //求凸包
{
public:
vector<Point>up, down;//上下半凸包(都是从左往右)
public:
Andrew(bool flag = false) { //flag表示刚好在凸包边上的点是否保留
this->flag = flag;
}
void push(Point p) //从左往右依次push所有的点
{
if (up.empty()) {
up.push_back(p), down.push_back(p), lefts.push_back(p), rights.push_back(p);
return;
}
if(p.x==lefts[0].x)lefts.push_back(p);
if (p.x > up.rbegin()->x) rights.clear();
rights.push_back(p);
if (p.x == up.rbegin()->x) {
if (p.y > up.rbegin()->y)up.rbegin()->y = p.y;
if (p.y < down.rbegin()->y)down.rbegin()->y = p.y;
return;
}
auto cmp = flag ? less : lesseq;
while (up.size() > 1 && cmp(slope(up[up.size() - 2], up[up.size() - 1]) , slope(up[up.size() - 1], p)))up.erase(up.begin() + up.size() - 1);
up.push_back(p);
while (down.size() > 1 && cmp(slope(down[down.size() - 1], p) , slope(down[down.size() - 2], down[down.size() - 1])))down.erase(down.begin() + down.size() - 1);
down.push_back(p);
}
vector<Point> getAll() //push之后获取整个凸包,从左下到左上,逆时针
{
vector<Point>ans = up;
if (flag) {
sort(rights.begin(), rights.end());
for (int i = 1; i < rights.size() - 1; i++)ans.push_back(rights[i]);
}
if (down.rbegin()->y != up.rbegin()->y)ans.push_back(*down.rbegin());
for (int i = down.size() - 2; i > 0; i--)ans.push_back(down[i]);
if (down.begin()->y != up.begin()->y)ans.push_back(*down.begin());
if (flag) {
sort(lefts.begin(), lefts.end());
for (int i = lefts.size() - 2; i > 0; i--)ans.push_back(lefts[i]);
}
return ans;
}
bool isStraightLine()//是竖线
{
return up.size() < 2;
}
bool isLine()//是线
{
if (isStraightLine())return true;
if (up[0].y != down[0].y)return false;
if (up[1].x != down[1].x || up[1].y != down[1].y)return false;
return true;
}
private:
vector<Point>lefts, rights;
bool flag;
};
class Geometry :public GeometryBase, public Bsearch<int> //几何
{
public:
Point minMaxWithSlope(vector<Point>&ps, double k, string type)//输入上(下)凸包,从左往右,type为max(min),求y-kx的最大(小)值在哪个点
{
if (ps.size() == 1)return ps[0];
this->ps = ps, this->k = k, this->type = type;
int id = find(0, ps.size() - 2);
return ps[id];
}
private:
virtual bool isOk(int x) const //若isOk(x)且!isOk(y)则必有y<x
{
return (type == "max") ? (slope(ps[x], ps[x + 1]) < k) : (slope(ps[x], ps[x + 1]) > k);
}
private:
string type;
vector<Point> ps;
double k;
};
else
CSU 1896 Symmetry(对称点集)
题目:
Description
We call a figure made of points is left-right symmetric as it is possible to fold the sheet of paper along a vertical line and to cut the figure into two identical halves.For example, if a figure exists five points, which respectively are (-2,5),(0,0),(2,3),(4,0),(6,5). Then we can find a vertical line x = 2 to satisfy this condition. But in another figure which are (0,0),(2,0),(2,2),(4,2), we can not find a vertical line to make this figure left-right symmetric.Write a program that determines whether a figure, drawn with dots, is left-right symmetric or not. The dots are all distinct.
Input
The input consists of T test cases. The number of test cases T is given in the first line of the input file. The first line of each test case contains an integer N, where N (1 <=N <= 1, 000) is the number of dots in a figure. Each of the following N lines contains the x-coordinate and y-coordinate of a dot. Both x-coordinates and y-coordinates are integers between −10, 000 and 10, 000, both inclusive.
Output
Print exactly one line for each test case. The line should contain 'YES' if the figure is left-right symmetric,and 'NO', otherwise.
Sample Input
3
5
-2 5
0 0
6 5
4 0
2 3
4
2 3
0 4
4 0
0 0
4
5 14
6 10
5 10
6 14
Sample Output
YES
NO
YES
这个题目是说,给一个整点集,判断是不是左右对称的。
要分2步进行,第一步找到唯一可能的对称轴的位置,第二步是判断点集是不是关于这条直线对称的。
第一步我是找最中间的若干个点,第二步我是把所有不在对称轴上面的点映射到一个整数,使得对称的点映射到一样的整数,不对称的点几乎不会映射到一样的整数,最后求出所有整数的异或,是0就对称,不是0就不对称。
我在比赛时提交的代码:
#include<iostream>
#include<algorithm>
using namespace std;
int kx1,kx2;
struct node
{
int x,y;
};
bool cmp(node n1,node n2)
{
return n1.x<n2.x;
}
int f(node nodd,int kx)
{
if(nodd.x*2<kx)return (kx-nodd.x*2)%123*nodd.y;
return (nodd.x*2-kx)%123*nodd.y;
}
int main()
{
int T,N,ans1,ans2;
node nod[1000];
cin>>T;
while(T--)
{
cin>>N;
for(int i=0;i<N;i++)cin>>nod[i].x>>nod[i].y;
sort(nod,nod+N,cmp);
kx1=nod[N/2].x*2;
kx2=nod[N/2].x+nod[(N-1)/2].x;
ans1=ans2=0;
for(int i=0;i<N;i++)
{
ans2=ans2^f(nod[i],kx2);
if(nod[i].x==kx1)continue;
ans1=ans1^f(nod[i],kx1);
}
if(ans1==0||ans2==0)cout<<"YES\n";
else cout<<"NO\n";
}
return 0;
}
实际上求对称轴还有更好的方法,不用最中间的点,用最左边和最右边的点。
第二步也不需要映射到整数,直接把点集存2份,一份从左往右排序,一份从右往左排序,然后一一比较是否对称即可。
新代码:
#include<iostream>
#include<algorithm>
using namespace std;
int T, N, kx;
struct node
{
int x, y;
};
node nod1[1000], nod2[1000];
bool cmp1(node n1, node n2)
{
if (n1.x == n2.x)return n1.y < n2.y;
return n1.x<n2.x;
}
bool cmp2(node n1, node n2)
{
if (n1.x == n2.x)return n1.y < n2.y;
return n1.x>n2.x;
}
bool ok()
{
for (int i = 0; i < N; i++)
{
if (nod1[i].y != nod2[i].y)return false;
if (nod1[i].x + nod2[i].x != kx)return false;
}
return true;
}
int main()
{
int left, right;
cin >> T;
while (T--)
{
cin >> N;
left = 10000, right = -10000;
for (int i = 0; i < N; i++)
{
cin >> nod1[i].x >> nod1[i].y;
nod2[i].x = nod1[i].x, nod2[i].y = nod1[i].y;
if (left>nod1[i].x)left = nod1[i].x;
if (right < nod1[i].x)right = nod1[i].x;
}
kx = left + right;
sort(nod1, nod1 + N, cmp1);
sort(nod2, nod2 + N, cmp2);
if (ok())cout << "YES\n";
else cout << "NO\n";
}
return 0;
}
力扣 356. 直线镜像
在一个二维平面空间中,给你 n 个点的坐标。问,是否能找出一条平行于 y 轴的直线,让这些点关于这条直线成镜像排布?
注意:题目数据中可能有重复的点。
示例 1:
输入:points = [[1,1],[-1,1]] 输出:true 解释:可以找出 x = 0 这条线。
示例 2:
输入:points = [[1,1],[-1,-1]] 输出:false 解释:无法找出这样一条线。
提示:
n == points.length
1 <= n <= 10^4
-10^8 <= points[i][j] <= 10^8
进阶:你能找到比 O(n2) 更优的解法吗?
class Solution {
public:
bool isReflected(vector<vector<int>>& points) {
int s=0,n=0;
map<int,map<int,int>>visit;
for(auto v:points){
if(visit[v[0]][v[1]])continue;
n++;
visit[v[0]][v[1]]=1;
s+=v[0];
}
int loc = s*2/n;
if(loc*n!=s*2)return false;
map<int,map<int,int>>m;
visit.clear();
for(auto v:points){
if(visit[v[0]][v[1]])continue;
visit[v[0]][v[1]]=1;
if(v[0]*2<loc)m[v[0]][v[1]]++;
if(v[0]*2>loc)m[loc-v[0]][v[1]]--;
}
for(auto &mi:m){
for(auto &p:mi.second){
if(p.second)return false;
}
}
return true;
}
};