vijos p1883 月光的魔法

来源:互联网 发布:gameloft的java小游戏 编辑:程序博客网 时间:2024/04/27 16:49

背景

影几欺哄了众生了
天以外——
月儿何曾圆缺

描述

有些东西就如同月光的魔法一般.

Luke是爱着vijos的.
他想为自己心爱的东西画些什么.

就画N个圆吧.
把它们的圆心都固定在x轴上.

圆与圆.
为了爱,两两不能相交.
为了爱,它们可以互相贴在一起.
内切或外切,都是允许的.

vijos的美丽,在于人心.
vijos的孩子们,一定能告诉大家:Luke画的圆究竟把平面分割成了多少块?

月光恬美地洒在大地上.
Luke知道,如果什么都不画,平面就只有一块.多美呢!
Luke知道,只画一个圆,平面就分成了两块.也很美呢!
但Luke还是要多画一些的,因为他真的深爱着vijos呢.

格式

输入格式

输入数据第一行:输出一个整数N,1<=N<=300,000.表示圆的个数.
之后N行,每一行有2个整数,x[i]和r[i]表示圆心固定在x[i]的位置,半径为r[i].
-1,000,000,000<=x[i]<=1,000,000,000
1<=r[i]<=1,000,000,000
所有圆都是唯一的,不会出现重叠.

输出格式

输出只有一行,要求输出平面被分割成了多少块.

样例1

样例输入1

2
1 3
5 1

样例输出1

3

样例2

样例输入2[复制]

32 21 13 1

样例输出2[复制]

5

样例3

样例输入3[复制]

47 5-9 11

样例输出3[复制]

6

    关于这道题,我确实花了不少功夫,这道题的关键在于所有的圆位置关系只有内切、外切、内含、外含四种关系,不存在两个圆相互交叉。所以理论上有n个圆,平面就被分成n+1个,之所以多是因为有些圆被其他几个圆分成了两个了,看懂这一点就成功了一点了。接下来就是代码问题了,我的思路就是先给圆排序,左端点优先,由小到大排。如果左端点相同半径大的在前面。这之后就请看代码吧,相关解释在代码里面,我觉得更清晰点。

记录信息

评测状态Accepted题目P1883 月光的魔法递交时间2015-02-27 12:25:33代码语言C评测机VijosEx消耗时间355 ms消耗内存4948 KiB评测时间2015-02-27 12:25:35

评测结果

编译成功

foo.c: In function 'result':
foo.c:32:15: warning: variable 'k' set but not used [-Wunused-but-set-variable]
{ int i,j,p,k,q,o;
^

测试数据 #0: Accepted, time = 0 ms, mem = 4944 KiB, score = 10

测试数据 #1: Accepted, time = 0 ms, mem = 4948 KiB, score = 10

测试数据 #2: Accepted, time = 0 ms, mem = 4948 KiB, score = 10

测试数据 #3: Accepted, time = 0 ms, mem = 4948 KiB, score = 10

测试数据 #4: Accepted, time = 15 ms, mem = 4948 KiB, score = 10

测试数据 #5: Accepted, time = 46 ms, mem = 4948 KiB, score = 10

测试数据 #6: Accepted, time = 62 ms, mem = 4948 KiB, score = 10

测试数据 #7: Accepted, time = 46 ms, mem = 4948 KiB, score = 10

测试数据 #8: Accepted, time = 62 ms, mem = 4944 KiB, score = 10

测试数据 #9: Accepted, time = 124 ms, mem = 4944 KiB, score = 10

Accepted, time = 355 ms, mem = 4948 KiB, score = 100

#include "stdio.h"#include "stdlib.h"struct yuan   //构造一个结构体来盛放相关信息{   int xin;   //记录圆心    int ban;   //记录半径    int left;  //记录左端点    int right; //记录右端点}a[300000];  /*1<=N<=300,000,所以构造一个盛300000元素的数组,在这说明一点,这个数组要在所有函数外面,不要放在主函                            数里,否则会报错,这是因为这个数组占用空间太大,主函数里的数组最多好像只能开到千位,当然这是c(目前我只学了c                           ,c++刚了解),别的语言还不清楚*/void result(struct yuan a[],int n);int cmp(const void *a,const void *b){   struct yuan *p=(struct yuan *)a;struct yuan *q=(struct yuan *)b;if(p->left!=q->left)   return (p->left)-(q->left);else   return (q->xin)-(p->xin);}int main() {   int N,i;while(scanf("%d",&N)!=EOF){   for(i=0;i<N;i++)   {   scanf("%d%d",&a[i].xin,&a[i].ban);       a[i].left=a[i].xin-a[i].ban;       a[i].right=a[i].xin+a[i].ban;   }   qsort(a,N,sizeof(a[0]),cmp);/*数组排序,如果是c++的话用sort会更方便也更为稳定,原因可以看看两个函数                                               写cmp函数的区别,一目了然*/   result(a,N);//这个用来寻找有几个圆被分成了两个}    return 0;   }void result(struct yuan a[],int n){   int i,j,p,k,q,o;int sum=n+1;  //sum用来记录平面的个数,初始值为n+1,有几个圆被平分就加上几for(i=0;i<n-1;i++){   if(a[i].left!=a[i+1].left) //如果一个圆被平分,那么排序后这个圆的下一个圆左端点肯定相同,否则不被平分    continue;            j=i+2;k=1;o=0;    if(j>=n) break;    while(a[i].right>=a[j].right)//如果一个圆被平分,那么平分它的圆肯定在它里面    {    p=j-1;        while(a[p].right>=a[j].right)//这是寻找第一个左端点不同且在a[p]圆外的圆     {    j++;          if(j>=n)             break;     }     if(a[p].right!=a[j].left)//如果一个圆平分,那么平分它的圆应该是连续的     {    k=0;          break;     }     q=j;     if((a[i].right==a[q].right)&&(a[q].left==a[p].right))//判断该圆是否符合被平分     {     o=1;           break;     }        j++;     if(j>=n)         break;    }    if(o)       sum++;}printf("%d\n",sum);}

0 0
原创粉丝点击