• 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
    ", 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
    ", ans);
        }
    }
    
  • 相关阅读:
    关于MapReduce中自定义分区类(四)
    关于MapReduce中自定义分组类(三)
    UiAutomator2.0
    Java_集合框架
    Python爬取指定重量的快递价格
    Java_面向对象
    Java_异常以及处理
    Java_File类
    Java_Scanner和System类
    Java_Runtime&Process&ProcessBuilder
  • 原文地址:https://www.cnblogs.com/AlvinZH/p/7761354.html
Copyright © 2020-2023  润新知