1660. 社交距离 II 知识点:搜索

109 阅读2分钟

样例解释

1660. 社交距离 II - AcWing题库 image.png D,F两头牛之间不可能存在传染,因为E牛没有被传染,因此可以确定:F牛一定是最开始感染的牛之一

D牛和E牛之间的距离四4,因为E牛没有被传染,所以可以确定: 感染半径R一定小于4

A牛和B牛之间的距离是4,C牛和D牛之间的距离是2,因为B牛和C牛之间不可能存在感染(距离为4,R小于4),因此A,B和C,D肯定是独立的。

假设R是C到D的距离(2),那么A就不可能感染B(距离为3)。

假设R是A到B的距离(3),那么A既可以感染B,C也可以感染D。

所以可以确定:感染距离就是3

最开始被感染的三头牛是 A C F 或 B D F或 A D F。 最开始被感染的牛的个数就是3

总结规律

如果当前牛是健康牛,那么最短感染距离R要么在其左边,要么在其右边(显而易见)。

我们就在其左边,右边去寻找答案(类似二分)

最后我们可以找出一个最短感染距离R。

解题思想

image.png

#include<bits/stdc++.h>
using namespace std;
const int M=1e5+10;
const int N=1010;
typedef pair<int,int>PII;
int vis[M];
PII a[N];
int n;


void bfs(int x,int R)
{
    queue<int> q;
    q.push(a[x].first);  //存一下第一个感染的牛的位置
    vis[x]=1;            //标记为走过
    
    while(!q.empty())
    {
        int t=q.front();
        q.pop();
        
        int left=t-R,right=t+R;
        for(int i=0;i<n;i++)
        {
            if(!vis[i]&&a[i].first>left&&a[i].first<right)  //如果没有越界并且没有被遍历过
            {
                q.push(a[i].first);  
                vis[i]=1;         //标记为走过
            }
        }
    }
}


int main()
{
    cin.tie(nullptr)->sync_with_stdio(false);
    cin>>n;
    for(int i=0;i<n;i++)
    {
        int x,y;cin>>x>>y;
        a[i]={x,y};
    }
    
    sort(a,a+n);
    
    //求最小感染半径R
    int R=0x3f3f3f3f;
    for(int i=0;i<n;i++)
    {
        //如果当前牛没有被感染
        if(a[i].second==0) 
        {
            //如果左边的牛被感染,R就更新为当前牛到左边牛的距离
            if(i-1>=0&&a[i-1].second==1) R=min(R,a[i].first-a[i-1].first);
           //如果右边的牛被感染,R就更新为当前牛到右边牛的距离
           if(i+1<n&&a[i+1].second==1) R=min(R,a[i+1].first-a[i].first);
        }
    }
    
    
    int res=0;
    for(int i=0;i<n;i++)
    {
        //如果当前牛是感染牛 并且 还没有被遍历过  ,那我们就从前往后推,看着头牛最多传染多少头牛
        if(a[i].second&&!vis[i])
        {
            res++;
            bfs(i,R);
        }
    }
    
    cout<<res<<endl;
    return 0;
}