zoukankan      html  css  js  c++  java
  • 小奇画画——BFS

    小奇画画

    题目描述

    红莲清泪两行欲吐半点却无
    如初是你杳然若绯雾还在水榭畔画楼处
    是谁衣白衫如初谁红裳如故
    ——《忆红莲》

    小奇想画几朵红莲,可惜它刚开始学画画,只能从画圆开始。小奇画了 (n) 个圆,它们的圆心都在 (x) 轴上,且两两不相交(可以相切)。现在小奇想知道,它画的圆把画纸分割成了多少块?(假设画纸无限大)

    输入格式

    第一行包括 (1) 个整数 (n)

    接下来 (n) 行,每行两个整数 (x)(r),表示小奇画了圆心在 ((x,0)),半径为 (r) 的一个圆。

    输出格式

    输出一个整数表示答案。

    样例

    样例输入

    4
    7 5
    -9 11
    11 9
    0 20
    

    样例输出

    6
    

    数据范围与提示

    对于 (30\%) 数据,(nleq 5000)

    对于 (100\%) 数据,(1leq nleq 300000), (-10^9leq xleq 10^9), (1leq rleq 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
    ",BFS()+n+1);
    	return 0;
    }
    
  • 相关阅读:
    NPOI json转Excel DataTable转Excel ,Excel转DataTable
    sqlhelper;
    C# DataSet数据导入Excel 修正版- .net FrameWork 4.0以上
    asp.net core 教程(七)-异常处理、静态文件
    asp.net core 教程(六)-中间件
    asp.net core 教程(五)-配置
    jQuery_3_过滤选择器
    jQuery_2_常规选择器-高级选择器2
    jQuery_2_常规选择器-高级选择器
    jQuery_2_常规选择器-进阶选择器
  • 原文地址:https://www.cnblogs.com/Rubyonly233/p/13387324.html
Copyright © 2011-2022 走看看