CF ECR 124-D. Nearest Excluded Points

 思路一:考虑到点的数量不超过200000,那么构成的最恶心的图形(即所有点都挤在一起)半径不会超过800,题目时限是4秒钟。莫非基础bfs能过?

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
pair<int,int> a[200005];
int n;
int dx[4]= {0,0,1,-1},dy[4]= {1,-1,0,0};
int qx[2000005],qy[2000005];
map<pair<int,int>,int> mp;
void bfs(pair<int,int> a)
{
    map<pair<int,int>,int> v;
    v[a]=1;
    int fx=0,rx=0,fy=0,ry=0;
    qx[rx++]=a.first,qy[ry++]=a.second;
    while(fx!=rx)
    {
        int xx=qx[fx++],yy=qy[fy++];
        for(int i=0; i<4; i++)
        {
            int nx=xx+dx[i],ny=yy+dy[i];
            if(v[{nx,ny}]==1)
                continue;
            if(mp[ {nx,ny}]==1)
                qx[rx++]=nx,qy[ry++]=ny,v[{nx,ny}]=1;
            else
            {
                cout<<nx<<' '<<ny<<endl;
                return;
            }
        }
    }
}
int main()
{
    ios::sync_with_stdio(0),cin.tie(0);
    int i,j;
    cin>>n;
    for(i=1; i<=n; i++)
    {
        cin>>a[i].first>>a[i].second;
        mp[ a[i]]=1;
    }
    for(i=1; i<=n; i++)
        bfs(a[i]);
    return 0;
}

愉快地在第9个数据点超时了。如何优化?典型思路是后续的计算可以考虑用先前的结果,节省时间,降低复杂度。如果先处理答案距离远的点,其结论并不能为近的点提供帮助。逆向考虑,先处理答案距离最近的点,例如距离1的点。当我们把距离1的点都处理结束后,剩下的点一定会被其他点包围,因为如果没被围上,那么它的距离也是1!!!

如果一个点被围住了,那么它的最近距离一定是其相邻4个点的最小值。因此采用类似拓扑排序的方法进行bfs,先预处理距离1的,然后递推得到距离2的,继续递推.......。

#include <bits/stdc++.h>
using namespace std;
pair<int,int> a[200005];
int n,dx[4]= {0,0,1,-1},dy[4]= {1,-1,0,0};
map<pair<int,int>,int> mp,v;/**< mp用于快速判定a[i],v用于bfs标记 */
map<pair<int,int>,pair<int,int>> ans;/**< 存答案 */
int main()
{
    ios::sync_with_stdio(0),cin.tie(0);
    int i,j;
    cin>>n;
    for(i=1; i<=n; i++)
    {
        cin>>a[i].first>>a[i].second;
        mp[ a[i]]=1;
    }
    queue<pair<int,int>>q;
    for(i=1; i<=n; i++)
    {
        for(j=0; j<4; j++)
        {
            int nx=a[i].first+dx[j],ny=a[i].second+dy[j];
            if(mp[{nx,ny}]==1)
                continue;
            ans[a[i]]=make_pair(nx,ny);
            v[a[i]]=1;/**< 表示a[i]已经入队 */
            q.push(a[i]);/**< 距离1的点入队,凡是没入队一定距离超过1,一定被包围,一定能由1的点bfs得到 */
        }
    }
    while(q.size())
    {
        int x=q.front().first,y=q.front().second;
        q.pop();
        for(j=0; j<4; j++)
        {
            int nx=x+dx[j],ny=y+dy[j];
            if(mp[{nx,ny}]==1&&v[{nx,ny}]==0)/**< {nx,ny}存在,且没有入队过 */
            {
                v[{nx,ny}]=1;
                ans[{nx,ny}]=ans[ {x,y}];
                q.push({nx,ny});
            }
        }
    }
    for(i=1; i<=n; i++)
        cout<<ans[a[i]].first<<' '<<ans[a[i]].second<<endl;
    return 0;
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值