[Luogu 3958] NOIP2017 D2T1 奶酪

NOIP2017 D2T1 奶酪(Luogu 3958)


人生第一篇题解,多多关照吧。



一个比较容易想到的搜索。我用的BFS。

因为涉及到开根,所以记得开double。

首先将所有的球按z值从小到大排序,如果最下方的球与底面相离,或是最上方的球与顶面相离,直接Pass。

接下来预处理,记得先初始化,对于每一组球(i,j),计算两球球心距离是否小于半径×2,用一个bool数组e[i][j]记录i能否到达j,避免BFS时重复计算。

我们会发现,可能不止一个球与底面相切或相交,也可能不止一个球与顶面相切或相交。

这就是说,BFS时起点和终点都可能不止一个,这给我们操作造成了一些麻烦(然而考场上我就这么硬搜的居然AC了)。

其实,通过建立「超级起点」和「超级终点」,可以把这个BFS变得正常。

我们可以用结构体数组的第0个元素表示「超级起点」,第n+1个元素表示「超级终点」。

预处理时,走一遍所有的球,如果当前球可以做起点,就连上当前球和超级起点,e[0][i]=e[i][0]=1;终点亦然。

在跑BFS的时候,对于每一个球,依次判断其能否到达0..n+1,当「超级终点」已被访问或队列已为空时结束搜索。

如果「超级终点」被访问过说明搜到了,可以到达;否则无法到达。

/*想象一下我打完这篇文章后把文中所有的「点」一个个改成「球」*/

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int MAXN=1010;
bool vis[MAXN],e[MAXN][MAXN];
double h,r;
int T,n;
struct ball
{
    double x,y,z;
    bool operator <(const ball &rhs) const
    {
        return z<rhs.z;
    }
}s[MAXN];
double dis(ball a,ball b)
{
    double t1=a.x-b.x,t2=a.y-b.y,t3=a.z-b.z;
    return sqrt(t1*t1+t2*t2+t3*t3);
}
void Init()
{
    memset(vis,0,sizeof vis);//初始化
    memset(e,0,sizeof e);//初始化
    for(int i=1;i<=n;++i)
    {
        if(s[i].z-r<=0)//超级起点
            e[0][i]=e[i][0]=1;
        if(s[i].z+r>=h)//超级终点
            e[n+1][i]=e[i][n+1]=1;
    }
    for(int i=1;i<n;++i)
        for(int j=i+1;j<=n;++j)
            e[i][j]=e[j][i]=dis(s[i],s[j])<=r*2;//i与j是否相连
}
void BFS()
{
    queue<int> q;
    q.push(0);
    vis[0]=1;
    while(!vis[n+1] && !q.empty())
    {
        int x=q.front();
        q.pop();
        for(int i=0;i<=n+1;++i)//遍历邻接点
            if(!vis[i] && e[x][i])//没被访问过且可到达
            {
                q.push(i);
                vis[i]=1;
            }
    }
}
int main(int argc,char *argv[])
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %lf %lf",&n,&h,&r);
        for(int i=1;i<=n;++i)
            scanf("%lf %lf %lf",&s[i].x,&s[i].y,&s[i].z);
        sort(s+1,s+n+1);//排序
        if(s[1].z-r>0 || s[n].z+r<h)//直接Pass的情况
        {
            printf("No\n");
            continue;
        }
        Init();//初始化+预处理
        BFS();
        printf(vis[n+1]?"Yes\n":"No\n");//判断是否搜到
    }
    return 0;
}

NOIP2017唯一AC的一道题啊。

时间: 2024-08-30 14:49:33

[Luogu 3958] NOIP2017 D2T1 奶酪的相关文章

[luogu P3960] [noip2017 d2t3] 队列

[luogu P3960] [noip2017 d2t3] 队列 题目描述 Sylvia 是一个热爱学习的女♂孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia 所在的方阵中有n \times mn×m名学生,方阵的行数为 nn,列数为 mm. 为了便于管理,教官在训练开始时,按照从前到后,从左到右的顺序给方阵中 的学生从 1 到 n \times mn×m 编上了号码(参见后面的样例).即:初始时,第 ii 行第 jj 列 的学生的编号是(i-1)

[SinGuLaRiTy] NOIP2017 提高组

[SinGuLaRiTy-1048] Copyright (c) SinGuLaRiTy 2018. All Rights Reserved. NOIP2017过了这么久,现在2018了才找到寒假这么一个空挡来写题解.哎,没办法,谁叫学校抓的紧呢. 序 | Before 这是我的最后一次NOIP. 因为是最后一次的原因吧,考前压力就蛮大的,再加上各种模拟赛,模板练习的轮番轰炸,走进考场时整个人都是“飘飘欲仙”的感觉~ 我的NOIP2017就在这种“飘飘欲仙”的氛围下开始了. 游记 | Blogs

NOIP2017 题解

QAQ--由于没报上名并没能亲自去,自己切一切题聊以慰藉吧-- 可能等到省选的时候我就没有能力再不看题解自己切省选题了--辣鸡HZ毁我青春 D1T1 小凯的疑惑 地球人都会做,懒得写题解了-- D1T2 时间复杂度 分类讨论+递归就行了,没啥思维含量,略. D1T3 逛公园 这题好劲啊-- D2T1 奶酪 \(O(n^2)\)暴力就行了,水题. D2T2 宝藏 看到数据范围一眼\(O^*(3^n)\)状压DP,其中\(3^n\)来自枚举子集的子集.做法好像有很多,比如ryf的做法就比我快了10倍

luogu P1433 吃奶酪

原题链接:https://www.luogu.org/problem/show?pid=1433 虽然是一道思维难度不大的DFS,但是这其中比较重要的是可行性剪枝(这是本蒟蒻做的第一道剪枝) 本题的优化点有不少:预处理两点之间的距离,用邻接矩阵存储,搜索时直接调用即可. 当目前走到的距离已经超过现有的最小值,那么就无需继续搜索下去,直接返回即可. (那些register 之类的,都是因为写了个死循环TLE了以为常数问题加的...) #include<cstdio> #include<cm

NOIP2017 Day2 T1 奶酪

题目描述 现有一块大奶酪,它的高度为 hhh ,它的长度和宽度我们可以认为是无限大的,奶酪 中间有许多 半径相同 的球形空洞.我们可以在这块奶酪中建立空间坐标系,在坐标系中, 奶酪的下表面为z=0z = 0z=0 ,奶酪的上表面为z=hz = hz=h . 现在,奶酪的下表面有一只小老鼠 Jerry,它知道奶酪中所有空洞的球心所在的坐 标.如果两个空洞相切或是相交,则 Jerry 可以从其中一个空洞跑到另一个空洞,特别 地,如果一个空洞与下表面相切或是相交,Jerry 则可以从奶酪下表面跑进空洞

[Luogu] 奶酪

https://www.luogu.org/problemnew/show/P3958 连边bfs / 并查集 #include <iostream> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; const int N = 1010; #define gc getchar() struct Node{ double x, y, z; }E[N]; i

解题报告:luogu P1433 吃奶酪

题目链接:P1433 吃奶酪 我感觉可以改成:[模板]TSP问题(商旅问题) 了. 爆搜\(T\)一个点,考虑状压\(dp\)(还是爆搜). 我们用\(dp[i][j]\)表示现在是\(i\)状态,站在了\(j\)点. 那什么是状态呢? 我们用一个零一串表示每一点有无被走过(\(0\)是没走过,\(1\)是已走过),那么转移方程就是: \[dp[i][j]=min(dp[i][j],dp[i\&((1<<n)-1-(1<<(j-1)))][k]+dis[j][k])\] 好

Luogu P3953【NOIP2017】逛公园【最短路+拓扑排序+动态规划】

题目描述 策策同学特别喜欢逛公园.公园可以看成一张NN个点MM条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,NN号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间. 策策每天都会去逛公园,他总是从1号点进去,从NN号点出来. 策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间.如果1号点 到NN号点的最短路长为dd,那么策策只会喜欢长度不超过d + Kd+K的路线. 策策

Luogu P3958 奶酪

#include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int n; double h,r; struct Cheese{ double x,y,z; //重载运算符 bool operator<(const Cheese &am