覆盖最多的直线上的点

本文介绍了一道经典的算法题目,旨在寻找使用固定长度的木条覆盖直线上的点的最大数量。通过合理的数据结构设计和算法优化,实现了高效的解决方案。

题库建设。。。


题目

已知X1,X2,X3,…,Xn是直线上的点,现希望用固定长度固定数量的木条去覆盖这些点,请编写程序求最多能够覆盖多少点?

输入要求:输入的第1行为三个整数n,m,k,分别表示直线上点的个数,木条的长度以及数量。输入的第2行有n个整数,表示坐标上的点。
输出要求:输出1行,为最多能够覆盖的点的个数。

输入样例:
8 3 2
10 7 6 1 -5 4 18 20

代码及注释

#include <iostream>
#include <algorithm>
using namespace std;

//用于存放线段的结构体
struct Node {
    int begin;//起点
    int end;//终点
    int count;//起点,终点以及之间的点的个数
};

Node *node;

int getMaxOverNum(int*point, int n, int m, int k);
int getNode(int*point, int begin, int end, int m);

bool comp(Node a,Node b) {//结构体按count排序
    return a.count > b.count;
}
int main() {

    int n;//直线上点的个数
    int m;//木条长度
    int k;//木条数量

    cin >> n >> m >> k;

    node = new Node[n];

    int *point = new int[n+1];

    for (int i = 0; i < n; i++) {
        cin >> point[i];
    }

    //从小到大排序
    sort(point, point + n);

    cout << getMaxOverNum(point, n, m, k) << endl;

    delete[]point;
    delete[]node;
    return 0;
}

int getMaxOverNum(int*point, int n, int m, int k) {
    //先排除边界条件
    if (m*k >= point[n - 1] - point[0]) {
        return n;//木块可以覆盖所有点
    }

    int num = getNode(point,0,n,m);

    if (0 == num ) {//如果没有匹配的线段,直接返回木块数量
        return k;
    }

    sort(node, node + num,comp);//从大到小排序

    cout << endl << "符合条件的线段:" << endl << "起始点 终点 数量" << endl;;
    for (int i = 0; i < num; i++) {
        cout << node[i].begin << " " << node[i].end << " " << node[i].count << endl;
    }

    int i = 1;
    int pre = 0;//用于比较的前一个索引
    int max = node[0].count;
    k--;//上面用掉一根木块了

    cout << endl << "选出来的线段:" << endl;
    cout << node[0].begin << " " << node[0].end << " " << node[0].count << endl;//测试代码

    while (k > 0 && i < num) {
        if (node[i].begin>node[pre].end || node[i].end < node[pre].begin) {
            k--;
            max += node[i].count;
            pre = i;//更新前一个索引
            cout << node[i].begin << " " << node[i].end << " " << node[i].count << endl;//测试代码
        }
        i++;
    }
    if (k > 0) {//这是为了
        max++;
    }
    return max;
}
int getNode(int*point, int begin, int end, int m) {
    int i = begin + 1;
    int pre = begin;
    int num = 0;
    point[end] = 0;//这一项本不存在,但为了不让他成为随机值,赋为0,也可以不加
    while (i < end) {
        if (point[i] - point[pre] <= m) {

            //这里的i==end-1是末尾元素的情况,也需要加入
            if (point[i + 1] - point[pre] > m || i==end-1) {
                node[num].begin = point[pre];
                node[num].end = point[i];
                node[num++].count = i - pre + 1;
                if (i - pre > 1) {//这里有一个回溯判断,保证不漏掉任何满足条件的线段
                    //即起点和终点间还有其他点
                    pre = i = pre + 1;
                }
                else {
                    pre = i;
                }
            }
        }
        else {
            pre = i;
        }
        i++;
    }
    return num;
}

运行示例:

1

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值