题库建设。。。
题目
已知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;
}
运行示例: