2016级算法第二次上机-A.画个圈圈诅咒你

890 画个圈圈诅咒你

思路

简单题。题目中的圆并没有什么实际作用,简化成线段重合问题会更好理解些。

暴力解法:使用双重for循环会T到想哭,记住最直接的方法一般是过不了题的。

解法一:二分查找。空间较小,时间更长。

把圆相离的问题转换为线段相交的问题,按先起点后终点的顺序升序排列这些圆(线段)。对于每条线段,向右找到第一条起点比这条线段终点大的线段,然后后面的线段都会满足要求,这里用二分去找。具体参考参考代码一。

解法二:线性查找。时间更短,空间更大。

同样是把圆相离的问题转换为线段的相交问题,把所有圆的左点和右点记录下来,并标记他们是左还是右,点的数量是圆的数量的两倍。排序:按所有点的位置排,如果点位置一样,则左边点优先(重要)。从头到尾遍历一次,用一变量(初始值为n)记录右边有多少个圆的左点,遇到左点时变量减1,遇到右点时用答案加上当前变量值,即是此圆右边与之相离的数量(左边的不须计算否则会产生重复)。具体参考参考代码二。

分析

两种方法都需要排序,排序时间 \(O(NlogN)\)

查找时间:解法一是 \(O(NlogN)\),解法二是 \(O(N)\)

参考代码一

//
// Created by AlvinZH on 2017/10/24.
// Copyright (c) AlvinZH. All rights reserved.
//

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

int n, x, r;

struct Circle {
    int left, right;

    bool operator < (const Circle a) const {
        if(left == a.left) return right < a.right;//其次右端
        return left < a.left;//左端优先
    }
}C[50005];

//二分查找右边最近的圆
int find(int l, int r, int x)
{
    int m;
    while(l <= r)
    {
        m = (l + r) >> 1;
        if(C[m].left < x) l = m + 1;
        else if(C[m].left >= x) r = m - 1;
    }
    return l;
}

int main()
{
    while(~scanf("%d",&n))
    {
        for(int i = 0; i < n; ++i) {
            scanf("%d %d", &x, &r);
            C[i].left = x - r;
            C[i].right = x + r;
        }
        sort(C, C+n);

        int ans=0;
        for(int i = 0; i < n-1; i++) {
            ans += n - find(i+1, n-1, C[i].right+1);
        }
        printf("%d\n", ans);
    }
}

参考代码二

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

int n, x, r;

struct Node {
    int x;//位置
    int isR;//标记左右

    bool operator < (const Node n) const {
        if(x < n.x) return true;
        else if(x == n.x && isR == 0) return true;
        return false;
    }
}N[100010];

int main()
{
    while(~scanf("%d", &n))
    {
        int num = 0;
        for (int i = 0; i < n; ++i) {
            scanf("%d %d", &x, &r);
            N[num].x = x - r;
            N[num].isR = 0;
            num++;
            N[num].x = x + r;
            N[num].isR = 1;
            num++;
        }
        sort(N, N+num);

        int ans = 0;
        int sum = n;
        for (int i = 0; i < num; ++i) {
            if(N[i].isR == 0) sum--;
            else ans += sum;
        }
        printf("%d\n", ans);
    }
}
posted @ 2017-10-31 14:30  AlvinZH  阅读(616)  评论(0编辑  收藏  举报