编程之美(七)光影切割问题

在一个平面内有一个矩形区域,直线穿过矩形可以将其分割为不同的区域,且在这个平面中不存在三条直线相交一点的情况。求当有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;

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值