计算几何

目录

直线

力扣 149. 直线上最多的点数

CSU 1407 最短距离

力扣 面试题 16.03. 交点

力扣 LCP 37. 最小矩形面积

三角形

CSU 1201 Triangle

CSU 1403 三角形面积

CSU 1591 三角形

正方形

力扣 2013. 检测正方形

力扣 面试题 16.13. 平分正方形

多边形

CSU 1007 矩形着色

力扣 469. 凸多边形

CSU 1159 中南才女

CSU 1204 Rectangles

POJ 2002 Squares

CSU 1011 Counting Pixels

力扣 1401. 圆和矩形是否有重叠

凸包

else

CSU 1896 Symmetry(对称点集)

力扣 356. 直线镜像


直线

力扣 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,其中 kb为整数 且 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;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值