小奇画画——BFS
作者:互联网
小奇画画
题目描述
红莲清泪两行欲吐半点却无
如初是你杳然若绯雾还在水榭畔画楼处
是谁衣白衫如初谁红裳如故
——《忆红莲》
小奇想画几朵红莲,可惜它刚开始学画画,只能从画圆开始。小奇画了 \(n\) 个圆,它们的圆心都在 \(x\) 轴上,且两两不相交(可以相切)。现在小奇想知道,它画的圆把画纸分割成了多少块?(假设画纸无限大)
输入格式
第一行包括 \(1\) 个整数 \(n\)。
接下来 \(n\) 行,每行两个整数 \(x\), \(r\),表示小奇画了圆心在 \((x,0)\),半径为 \(r\) 的一个圆。
输出格式
输出一个整数表示答案。
样例
样例输入
4
7 5
-9 11
11 9
0 20
样例输出
6
数据范围与提示
对于 \(30\%\) 数据,\(n\leq 5000\);
对于 \(100\%\) 数据,\(1\leq n\leq 300000\), \(-10^9\leq x\leq 10^9\), \(1\leq r\leq 10^9\)。
思路
第一眼看到题一直没看出来能用 \(BFS\),没想到能用图论做。
很容易发现有特殊情况:
当两个小圆的半径加起来等于大圆的半径时,会多分出一块纸片,所以我们只需要求出特殊情况的次数,最后加上 \(n+1\) 就可以了。
怎么求出特殊情况的次数呢,就跟我们的图论扯上关系了,将大圆向被它包含的小圆建边,遍历它走到的点计算半径和。
首先将每个圆排序,将左端点从小到大排序,将右端点从大到小排序,这样我们就可以先遍历到大圆,建边即可。
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=3e5+50,INF=0x3f3f3f3f;
inline int read(){
int x=0,w=1;
char ch;
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') w=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*w;
}
int n;
int rd[maxn];
struct Node{
int x,R;
int l,r;
}a[maxn];
vector<int> vec[maxn];//存边的边表
bool cmp(Node a,Node b){//排序
if(a.l==b.l){
return a.r>b.r;
}else{
return a.l<b.l;
}
}
int BFS(){
int ans=0;
queue<int> q;
for(int i=1;i<=n;i++){
if(rd[i]==0){
q.push(i);
}
}
while(!q.empty()){
int u=q.front();
q.pop();
int tot=0;
for(int i=0;i<vec[u].size();i++){
int v=vec[u][i];
tot+=a[v].R;//计算半径和
q.push(v);
}
if(tot==a[u].R){//有特殊情况
ans++;
}
}
return ans;
}
signed main(){
n=read();
for(int i=1;i<=n;i++){
a[i].x=read(),a[i].R=read();
a[i].l=a[i].x-a[i].R;//左端点
a[i].r=a[i].x+a[i].R;//右端点
}
sort(a+1,a+n+1,cmp);
stack<int> s;
for(int i=1;i<=n;i++){
while(!s.empty()){
int t=s.top();
if(a[i].r<=a[t].r){//被包含在里面
vec[t].push_back(i);//建边
rd[i]++;
break;
}
s.pop();//不被包含在里面,出栈
}
s.push(i);
}
printf("%lld\n",BFS()+n+1);
return 0;
}
标签:10,ch,leq,小奇,样例,BFS,int,排序,画画 来源: https://www.cnblogs.com/Rubyonly233/p/13387324.html