问题2
题意描述
基站布置问题
思路
可以使用贪心法来解决。先按照每艘船到x轴距离为d的投影点(右侧那个)对船只进行排序。然后遍历每艘船,如果该船没有被任何一个基覆盖到,那么就在上述的那个点放置一个基站。 实质上就是让没覆盖到的船只处于新基站的最边缘位置,这样这个基站能贪到后续最多的基站。
算法复杂度 O(nlogn)
代码
#include <iostream>
#include <cstring>
#include <math.h>
using namespace std;
// 浮点误差
const double minINF = 0.00000000001;
// 最大船只数量
const int maxN = 10000;
// 记录船只的横纵坐标的数组,ships[i][0]为横坐标、ships[i][1]为纵坐标
double ships[maxN + 1][2];
// 记录基站的横坐标的数组,很明显最多也只能有和船只数量一样多的基站
// 可能翻译为 Base Station 好一点,但是这个比较简单
double cells[maxN + 1];
int cell_num;
// 共有n艘船只
int n;
// 基站可以覆盖半径为d的区域
int d;
// 对船只的位置进行排序
// 注意要按照可允许的最远基站点位置排序
int compareByPosition(const void* a, const void* b)
{
double temp = ((double*)a)[0] + sqrt(d * d - ((double*)a)[1] * ((double*)a)[1]) - (((double*)b)[0] + sqrt(d * d - ((double*)b)[1] * ((double*)b)[1]));
// 注意浮点数比较注意预留一定的精度判断
if(-minINF <= temp && temp <= minINF) {
return 0;
}
else if(temp < 0) {
return -1;
}
else {
return 1;
}
}
// 判断该船只是否已被覆盖
bool isCover(double px, double py) {
for(int ci = 0; ci < cell_num; ci++) {
double temp = (px - cells[ci]) * (px - cells[ci]) + py * py - d * d;
if(temp <= minINF) {
return true;
}
}
return false;
}
int main(int argc, const char * argv[]) {
// 共m组测试用例
int m;
cin >> m;
while((m--) > 0) {
// 初始化
memset(ships, 0, sizeof(ships));
memset(cells, 0, sizeof(cells));
cell_num = 0;
// 输入船只数量和基站可覆盖范围半径
cin >> n >> d;
// 输入船只坐标
for(int ni = 0; ni < n; ++ni) {
cin >> ships[ni][0] >> ships[ni][1];
}
// 根据位置对船只进行排序
qsort(ships, n, sizeof(double) * 2, compareByPosition);
// 按顺序遍历每艘船只进行贪心法
for(int ni = 0; ni < n; ++ni) {
// 判断该船只有没有被覆盖,没有的话给它安排一个基站
if(!isCover(ships[ni][0], ships[ni][1])) {
cells[cell_num] = ships[ni][0] + sqrt(d * d - ships[ni][1] * ships[ni][1]);
++cell_num;
}
}
// 输出结果
cout << cell_num << endl;
}
return 0;
}
问题4
题意描述
黑白连线
思路
(1)维护一个黑点栈和白点栈; (2)按顺序遍历每一个点,如果遇到一个白点,就查看当前黑点栈是否为空,非空的话就将将该白点与黑点栈顶黑点连接(因为栈是先入先出,所以栈顶黑点就是离该白点最近的未连接的黑点);遇到黑点也做类似的操作。
算法复杂度 O(n)
代码
#include <iostream>
#include <stack>
using namespace std;
int main(int argc, const char * argv[]) {
// 共m组测试数据
int m;
cin >> m;
while((m--) > 0) {
// 输入黑白点的数量n,即共有2*n个点
int n;
cin >> n;
// 创建点数组points并输入点
int* points = new int[2*n];
for(int pi = 0; pi < 2 * n; ++pi) {
cin >> points[pi];
}
// 创建黑白点栈
stack<int> whitePoints;
stack<int> blackPoints;
// 初始化结果
int result = 0;
// 开始贪心算法
for(int pi = 0; pi < 2 * n; ++pi) {
// 如果是白色的点
if(points[pi] == 0) {
// 如果没有黑点待分配,就将这个白点入栈,等一个最近的黑点来挑它
if(blackPoints.empty()) {
whitePoints.push(pi);
}
// 如果黑点栈中有未分配的黑点,就选择栈顶元素(也就是最近的黑点)
else {
result += (pi - blackPoints.top());
blackPoints.pop();
}
}
// 如果是黑色的点
else {
// 如果没有白点待分配,就将这个黑点入栈,等一个最近的白点来挑它
if(whitePoints.empty()) {
blackPoints.push(pi);
}
// 如果白点栈中有未分配的白点,就选择栈顶元素(也就是最近的白点)
else {
result += (pi - whitePoints.top());
whitePoints.pop();
}
}
}
// 输出结果并释放资源
cout << result << endl;
delete [] points;
}
return 0;
}