MorsLin 的博客

MorsLin 的博客

前事不忘,后事之师

题解 P3958 【奶酪】

posted on 2018-04-17 21:36:04 | under 题解 |

谨以此题来纪念我爆炸的NOIp2017


这个题虽然很多人说是并查集,但是搜索也是毫无压力的,考场搜索细节写挂,爆了个不上不下的80分。今天无意看到这道题,终于AC

  • 首先这道题要考虑一下精度问题,虽然出题人没有毒瘤的卡精度,但还是要值得注意。解决方法也很简单,去除开方运算,而是将半径平方,即$2r$ ---> $4r^2$,这样就OK了。不过要记得用$\rm long\;long$,不然会爆$\rm int$

  • 然后考虑如何搜索,我是将每组数据用前向星存成图,然后搜这张图。这道题有一个很特别的地方,那就是它不用回溯,因为如果一个点到不了终点,那再次搜到的话也还是到不了终点,所以我们为什么要将它再搜一遍呢?直接丢掉就好了

上代码

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
inline int read() //快读 
{
    int k=0,f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar())
    if(c=='-')f=-1;
    for(;isdigit(c);c=getchar())
    k=k*10+c-48;
    return k*f;
}
struct zzz{  //存空洞的坐标 
    ll x,
       y,
       z;
}che[1001];
inline ll f(zzz x,zzz y)  //计算空洞距离 
{
    return (x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y)+(x.z-y.z)*(x.z-y.z);
}
struct hhh{  //存图 
    int f,
        t,
        nex;
}e[2000001];  int head[1001]; int tot;
inline void add(int x,int y)  //前向星 
{
    e[++tot].f=x;
    e[tot].t=y;
    e[tot].nex=head[x];
    head[x]=tot;
}
int s[1001],flag; bool en[1001],vis[1001]; 
//s:可以当作起点的空洞  flag:可以当作起点的空洞的个数  en:终点空洞  vis:这个点是否走过 
bool ans;  //判断能否到达上表面 
void dfs(int str)  //搜索主体 
{
    if(en[str])  //找到终点就不用搜了 
    {
        ans=1;  return ;
    }
    for(int i=head[str];i;i=e[i].nex)  //向下寻找能搜的点 
      if(!vis[e[i].t])
      {
          vis[e[i].t]=1;  //直接标志为搜过,不再回溯 
          dfs(e[i].t);  //向下搜索 
          if(ans)
            return ;
      }
}
int main()
{
    int t; t=read();
    int n; ll h,r;
    while(t--)
    {
        tot=0; memset(head,0,sizeof(head)); ans=0;
        flag=0; memset(en,0,sizeof(en)); memset(vis,0,sizeof(vis)); //清空所有变量 
        n=read(),h=read(),r=read();
        for(int i=1;i<=n;i++)  //输入数据 + 处理成图 
        {
            che[i].x=read(),che[i].y=read(),che[i].z=read();

            if(che[i].z<=r) //如果z>=半径,那么这个空洞和下表面接触,将它加入起点 
              s[++flag]=i;
            if(che[i].z>=h-r) //同理,如果z>=h-r,那它和上表面接触,将它加入终点 
              en[i]=1;
            for(int j=1;j<i;j++)
              if(f(che[i],che[j])<=4*r*r) //防止精度损失 
              {
                  add(i,j);  add(j,i);
              }
        }
        // 搜索 + 输出 
        bool jjj=0;
        for(int i=1;i<=flag;i++)
        {
            dfs(s[i]);
            if(ans)
            {
                printf("Yes\n");
                jjj=1;
                break;
            }
        }
        if(!jjj)
          printf("No\n");
    }
    return 0;
}
  • 打个广告吧

 在下的洛谷博客博客园博客