背景
影几欺哄了众生了
天以外——
月儿何曾圆缺
描述
有些东西就如同月光的魔法一般.
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
21 3
5 1
样例输出1
3样例2
样例输入2[复制]
3 2 2 1 1 3 1
样例输出2[复制]
5
样例3
样例输入3[复制]
4 7 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);
}