leetcode算法问题

108 阅读3分钟

问题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;
}
​
​