51nod 1278 相离的圆(排序+修改步长)

题目意思:

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1278

平面上有N个圆,他们的圆心都在X轴上,给出所有圆的圆心和半径,求有多少对圆是相离的。

例如:4个圆分别位于1, 2, 3, 4的位置,半径分别为1, 1, 2, 1,那么{1, 2}, {1, 3} {2, 3} {2, 4} {3, 4}这5对都有交点,只有{1, 4}是相离的。

Input

第1行:一个数N,表示圆的数量(1 <= N <= 50000)
第2 - N + 1行:每行2个数P, R中间用空格分隔,P表示圆心的位置,R表示圆的半径(1 <= P, R <= 10^9)

Output

输出共有多少对相离的圆。

Input 示例

4
1 1
2 1
3 2
4 1

Output 示例

1

题目分析:

/**

*方法一

*将圆分为左右短点,用线段表示,现在就变形为了线段相交问题

*左端点left=c-r,右端点right=c+r,按左端点升序排序,相等的话

按右端点升序排序,然或进行扫描,对于每一条线段i,当以后的某一条

*线段j的左端点大于i的右端点,则以后的所有线段与其(i)相离

*时间复杂度为O(nlog(n)+n^2)

*此题的数据是50000,正常的O(n*n)的时间肯定会超时

*现在我们可以考虑改变步长的方法优化算法(只能降低系数,但有时确实很好),

*我在查询的时候优化,另步长为100,如果当前的j满足条件,则最先满足

*条件的j一定在j之前的100个以内,只需要在查询j的前100个即可,

*时间复杂度O(n*log(n)+n*(n/100+100));对于本题将你n^2的系数降低了尽100倍

*************************************************************************

*方法二 感谢Dava

*把所有圆的起点和终点放在一个数组中,按大小排序(圆的左右短点表示)

*如果某个圆的起点与另一个圆终点大小相等,则把起点排在前面

*定义结构体

*struct{

*  long long d;//线段的节点

*  int tmp;//标记起点(0)和终点(1),

*}

*记录所有的起点和终点直接快排,

*令num=圆的个数,遇到起点num--,遇到终点sum+=num

*/

AC代码,方法1

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
struct node{
    int left,right;
};
node p[50005];
int cmp(node a,node b){
    if(a.left<b.left) return 1;
    else if(a.left==b.left&&a.right<b.right) return 1;
    return 0;
}
int main()
{
    int c,r,n;
    while(cin>>n){
        for(int i=0;i<n;i++){
            cin>>c>>r;
            p[i].left=c-r;
            p[i].right=c+r;
        }
        sort(p,p+n,cmp);
        int i,j,sum=0,k;
        for(i=0;i<n;i++){
            for(j=i+100;j<n;j+=100){//步长为100
                if(p[j].left>p[i].right) break;
            }
            if(j>n) j=n;
            for(k=j-1;k>0&&k>j-101;k--){//扫描之间100个元素
                if(p[k].left<=p[i].right){
                    sum+=n-(k+1); break;
                }
            }
        }
        cout<<sum<<endl;
    }
    return 0;
}

AC代码,方法二

#include<iostream>
#include<algorithm>
using namespace std;
struct node{
    long long d;//线段的节点
    int flag;//标记起点(0)和终点(1),
}p[100005];
int cmp(node a,node b){
    if(a.d<b.d) return 1;
    else if(a.d==b.d&&a.flag==0) return 1;
    return 0;
}
int main()
{
    int c,r,n;
    while(cin>>n){
        int k=0;
        for(int i=0;i<n;i++){
            cin>>c>>r;
            p[k].d=c-r;
            p[k++].flag=0;//起点
            p[k].d=c+r;
            p[k++].flag=1;//终点
        }
        //cout<<k<<endl;
        sort(p,p+k,cmp);
        int sum=0,num=n;
        for(int i=0;i<k;i++){
            //cout<<p[i].d<<" "<<p[i].flag<<endl;
            if(p[i].flag==0) num--;
            else if(p[i].flag==1) sum+=num;
        }
        cout<<sum<<endl;
    }
    return 0;
}
时间: 2024-08-22 00:38:14

51nod 1278 相离的圆(排序+修改步长)的相关文章

51NOD 1278 相离的圆(二分 + 排序)

传送门 平面上有N个圆,他们的圆心都在X轴上,给出所有圆的圆心和半径,求有多少对圆是相离的. 例如:4个圆分别位于1, 2, 3, 4的位置,半径分别为1, 1, 2, 1,那么{1, 2}, {1, 3} {2, 3} {2, 4} {3, 4}这5对都有交点,只有{1, 4}是相离的. Input 第1行:一个数N,表示圆的数量(1 <= N <= 50000) 第2 - N + 1行:每行2个数P, R中间用空格分隔,P表示圆心的位置,R表示圆的半径(1 <= P, R <=

51nod 1278 相离的圆

基准时间限制:1 秒 空间限制:131072 KB 分值: 10 难度:2级算法题 平面上有N个圆,他们的圆心都在X轴上,给出所有圆的圆心和半径,求有多少对圆是相离的. 例如:4个圆分别位于1, 2, 3, 4的位置,半径分别为1, 1, 2, 1,那么{1, 2}, {1, 3} {2, 3} {2, 4} {3, 4}这5对都有交点,只有{1, 4}是相离的. Input 第1行:一个数N,表示圆的数量(1 <= N <= 50000) 第2 - N + 1行:每行2个数P, R中间用空格

51nod - 1278 相离的圆 (二分)

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1278 因为圆心都在x轴上,把每个圆转化成线段后,按线段的起点排序,那么对于每个圆都要从后面找出起点大于当前圆转化成的线段终点的一个点,这个点之后的圆都会与当前圆相离. 因为按起点排序所以可以二分求解. 发现自己二分写的乱七八糟的. 1 #include <iostream> 2 #include <cstdio> 3 #include <cmath&

1278 相离的圆(51nod)

题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1278 这道题需要用到两个姿势第一将圆相离的模型转换成线段和线段之间不想交,然后还有一个就是修改循环变量的步长.达到降低时间复杂度的效果,不过只能降低系数,并不能降低次数= = #include<stdio.h> #include<string.h> #include<iostream> #include<algorithm>

51Nod1278 相离的圆

Problem 平面上有N个圆,他们的圆心都在X轴上,给出所有圆的圆心和半径,求有多少对圆是相离的. 例如:4个圆分别位于1, 2, 3, 4的位置,半径分别为1, 1, 2, 1,那么{1, 2}, {1, 3} {2, 3} {2, 4} {3, 4}这5对都有交点,只有{1, 4}是相离的. Solution 注意圆心在坐标轴上,之前因为没看到这句话把题跳了. 然后就可以转化为线段,按照左端点排序,i代表线段循环,二分求左端点在第i条线段右端点左边的最后一个线段,他后面的线段就是相离的,加

51nod 1589 移数博弈【桶排序+链表】

1589 移数博弈 基准时间限制:1 秒 空间限制:262144 KB 分值: 80 难度:5级算法题 小A和小B在玩一个游戏. 他们拥有一个数列. 小A在该数列中选择出最大的那个数,然后移出该数列. 小B在剩下的数列中选择出最大的那个数,并乘上小A的那个值,作为他的答案. 那么现在问题来了. 他们现在想换一种玩法,把该数列长度大于等于2的区间(即n*(n-1)/2个区间)单独作为一个数列拿出来,然后做一次上述的游戏,然后计算出小B所有的答案,考虑到输出那么多数比较困难,因此他们想知道所有答案和

discuz x2 个人资料项排序问题解决方法、添加自定义字段、修改栏目名称和介绍

第一次写文章,希望与人提供方便同时,别误人子弟,自己研究的,大家看不懂只改文件就可以了,如果发现不对的地方请回复或直接通知我,谢谢,本来想在discuz论坛上发的,不懂版规也没时间看版规,怕发错,隔小jj怎么办? (一)个人资料项排序问题解决方法 首先说明一下情况,昨天在做网站的个人资料项时发现后台可以设置排序的(图一)数字越大越往下,但是用户页面(图2)却是一直不变,比如新添加的字段想让他排在第一,在网上找了好久都没有搜索到(或许是我不会搜索)看了大半天,看懂了点, (图2) (图2 修改后的

Wordpress 修改 Page 页面默认排序

默认 Wordpress 的 Page 页面是按照 Title 升序排序的,如果创建的页面很多,使用起来会很不方面,所以可以通过将以下代码添加到 functions.php 中,实现将 Page 页面按照 Date 倒序 // 将 Page 页面默认排序修改为按照 Date 倒序 function set_page_order_in_admin( $wp_query ) { global $pagenow; if ( is_admin() && 'edit.php' == $pagenow

算法实验1--算法排序比较

一.实验目的: 比较至少4种排序算法的执行效率.已学过的算法:起泡排序.选择排序.插入排序.shell排序,归并排序.快速排序等. 二.实验要求: 1.从中选择至少4中排序算法,写成独立的函数进行调用. 2.参与排序的数据不少于5000个,要求用数据文件存储随机产生的数据. 3.要求在main()函数中调用以上函数,并输出各排序算法所用时间. 三.问题描述: 通过至少四种排序算法设计,功能实现,计算出完成随机生成的至少5000个数所需要的时间,并比较各种算法的效率. 四.算法分析: 随机数存入文