Luogu P3958 奶酪

这题作为NOIP2017提高组Day2T1的题目,尽管大家认为这是一道水题,但我感触颇丰…

思路:

这题思路很多,什么DFS啦,BFS啦都可以做。但我还是推荐并查集,有人说并查集会卡常数,但只要你写得好,就不会TLE了…

做题经历:

我刚开始做这题时看了下数据,很显然可以用搜索,于是我手打了一遍DFS,可是交到洛谷评测时得了50分,后面五个点RE,反正可以下测试数据,就下了一下测试点#6,一看:10组数据,每一组1000个洞,我默默地不吱声了…

重新分析算法的我想到了我最近学的并查集,呵呵,应该是可以的,反正有洞连接就合并就好了。于是我就手打了一遍并查集,再次交到洛谷,0分,全WA和RE,我准备重构代码…

后面我重打完代码后再交到洛谷后还以为会得部分分,结果居然AC了,不可思议…

代码及分析:

一个基本的并查集,如果两个洞相连就合并,最后找到底面的洞和顶面的洞判断一遍,在判断之前可以sort一遍,以简化常数。对于两个球而言,如果两个球连通相当于球心距大于半径之和,就可以简化为普通合并…

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
class sph{
    public:
        ll x,y,z;
};
sph hole[100001];
bool has_solution;
ll boss[100001],test,cnt,height,rad;
ll tp,bt,top[1001],bottom[1001];
inline void setup()
{
    for(register int i=1;i<=cnt;i++)
    {
        boss[i]=i;
    }
}
inline ll findb(ll node)
{
    if(node==boss[node])
    {
        return node;
    }
    else
    {
        boss[node]=findb(boss[node]);
        return boss[node];
    }
}
inline void Union(ll na,ll nb)
{
    ll ba,bb;
    ba=findb(na);
    bb=findb(nb);
    if(ba!=bb)
    {
        boss[bb]=ba;
    }
}
inline bool Find(ll na,ll nb)
{
    return findb(na)==findb(nb);
}
inline double dist(sph a,sph b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z));
}
inline bool cmp(sph a,sph b)
{
    return a.z<b.z;
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>test;
    for(register int i=0;i<test;i++)
    {
        cin>>cnt>>height>>rad;
        has_solution=0;
        memset(boss,0,sizeof(boss));
        tp=bt=0;
        memset(top,0,sizeof(top));
        memset(bottom,0,sizeof(bottom));
        setup();
        for(register int j=1;j<=cnt;j++)
        {
            cin>>hole[j].x>>hole[j].y>>hole[j].z;
            if(hole[j].z-rad<=0)
            {
            	bottom[bt++]=j;
            }
            if(hole[j].z+rad>=height)
            {
            	top[tp++]=j;
            }
            for(register int k=1;k<=j;k++)
        	{
        		if(dist(hole[j],hole[k])<=2*rad)
        		{
        			Union(j,k);
                }
            }
        }
        for(register int j=0;j<bt;j++)
        {
            for(register int k=0;k<tp;k++)
            {
                if(Find(bottom[j],top[k]))
                {
                    has_solution=1;
                    break;
                }
            }
        }
        if(has_solution)
        {
            cout<<"Yes"<<endl;
        }
        else
        {
            cout<<"No"<<endl;
        }
    }
} 

总之,这道题还是很水的…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值