在一个平面内有一个矩形区域,直线穿过矩形可以将其分割为不同的区域,且在这个平面中不存在三条直线相交一点的情况。求当有N条直线穿过矩形时,它被分割为多少个区域?
例如: 图中有两条直线将矩形分割为 4 4 4 个区域。
分析与思路
思路一
两条直线:
1
1
1个交点,
4
4
4个区域
三条直线:
2
2
2个交点,
6
6
6个区域
三条直线:
3
3
3个交点,
7
7
7个区域
四条直线:
4
4
4个交点,
9
9
9个区域
四条直线:
5
5
5个交点,
10
10
10个区域
由此可以推出:
n
u
m
=
N
+
m
+
1
num = N + m + 1
num=N+m+1(
n
u
m
num
num表示区域数,
N
N
N表示直线数,
m
m
m表示交点数)
思路:用两点式表示一条直线,通过该直线可求出与其它直线的交点,判断该交点是否落在(
A
,
B
A, B
A,B)范围内,如果是则
+
1
+1
+1,得到交点数
c
n
t
cnt
cnt,并推出最终的区域数:
c
n
t
+
N
+
1
cnt + N + 1
cnt+N+1
思路二
思路:由上图,可知右边直线的顺序为(
c
,
b
,
a
c, b, a
c,b,a),形成的逆序对为(
c
,
b
c, b
c,b), (
c
,
a
c, a
c,a), (
b
,
a
b, a
b,a),恰巧为其交点的数量;当我们已知右边直线的序列,我们只需求逆序对数目即可得出其交点数量,然后按照思路一的推导可得出区域数
逆序对数目求法:归并排序的思想;在归并排序的过程中比较start与mid + 1的大小,从而求出逆序对的数量
类似题目:【剑指offer】数组中的逆序对
代码
思路一
#include <iostream>
using namespace std;
#define Left 0
#define Right 9
typedef struct node {
double x1, y1, x2, y2;
}line;
line test_lines[] = {{1, 1, 2, 2}, {0, 3, 9, 2}, {0, 4, 9, 7}, {0, 1, 9, 3}};
int test_len = 4;
//line test_lines[] = {{2, 1, 5, 1}, {5, 5, 8, 5}, {8, 1, 2, 7}};
//int test_len = 3;
bool judge(line line1, line line2, double &x, double &y) {
double k1 = 0, b1 = 0, k2 = 0, b2 = 0;
if (line1.x1 - line1.x2 != 0 && line2.x1 - line2.x2 != 0) {
k1 = (line1.y1 - line1.y2) / (line1.x1 - line1.x2);
k2 = (line2.y1 - line2.y2) / (line2.x1 - line2.x2);
if (k1 == k2)
return false;
b1 = line1.y1 - k1 * line1.x1;
b2 = line2.y1 - k2 * line2.x1;
x = (b2 - b1) / (k1 - k2);
y = k1 * x + b1;
}
else if (line1.x1 - line1.x2 == 0 && line2.x1 - line2.x2 == 0)
return false;
else if (line1.x1 - line1.x2 == 0 && line2.x1 - line2.x2 != 0) {
k2 = (line2.y1 - line2.y2) / (line2.x1 - line2.x2);
b2 = line2.y1 - k2 * line2.x1;
x = line1.x1;
y = k2 * x + b2;
}
else if (line1.x1 - line1.x2 != 0 && line2.x1 - line2.x2 == 0) {
k1 = (line1.y1 - line1.y2) / (line1.x1 - line1.x2);
b1 = line1.y1 - k1 * line1.x1;
x = line2.x1;
y = k1 * x + b1;
}
return true;
}
int Cal(line test_lines[], int test_len) {
double x, y;
int cnt = 0;
for (int i = 0; i < test_len; ++i) {
for (int j = i + 1; j < test_len; ++j) {
bool flag = judge(test_lines[i], test_lines[j], x, y);
if ( flag && x > Left && x < Right && y > Left && y < Right) {
cout << x << " " << y << endl;
cnt++;
}
}
}
cnt += test_len + 1;
return cnt;
}
int main() {
int num = Cal(test_lines, test_len);
cout << num << endl;
return 0;
}
测试结果:
line test_lines[] = {{1, 1, 2, 2}, {0, 3, 9, 2}, {0, 4, 9, 7}, {0, 1, 9, 3}};
int test_len = 4;
line test_lines[] = {{2, 1, 5, 1}, {5, 5, 8, 5}, {8, 1, 2, 7}};
int test_len = 3;
思路二
#include <iostream>
using namespace std;
int test_line[] = {4, 1, 3, 2};
int len = 4;
//int test_line[] = {3, 1, 4, 2, 7, 6, 8, 5};
//int len = 8;
int getInverse(int test_line[], int start, int end) {
if (start < end) {
int mid = (start + end) >> 1;
int left = getInverse(test_line, start, mid);
int right = getInverse(test_line, mid + 1, end);
int k = 0;
int* copy = new int[end - start + 1];
int i = start, j = mid + 1;
int cnt = 0;
while (i <= mid && j <= end) {
if (test_line[i] > test_line[j]) {
cnt += mid - i + 1;
copy[k++] = test_line[j++];
}
else {
copy[k++] = test_line[i++];
}
}
while (i <= mid)
copy[k++] = test_line[i++];
while (j <= end)
copy[k++] = test_line[j++];
k = 0;
for (int i = start; i <= end; ++i)
test_line[i] = copy[k++];
delete []copy;
return left + right + cnt;
}
else {
return 0;
}
}
int main() {
int num = getInverse(test_line, 0, len - 1);
for (int i = 0; i < len; ++i)
cout << test_line[i] << " ";
cout << endl << num + len + 1 << endl;
return 0;
}
测试结果:
int test_line[] = {4, 1, 3, 2};
int len = 4;
int test_line[] = {3, 1, 4, 2, 7, 6, 8, 5};
int len = 3;