Week2Day2C:广度优先搜索练习【2023 安全创客实践训练|笔记】

内容为武汉大学国家网络安全学院2022级大一第三学期“996”实训课程中所做的笔记,仅供个人复习使用,如有侵权请联系本人,将与15个工作日内将博客设置为仅粉丝可见。

目录

一维坐标的移动

输入格式

输出格式

样例输入

样例输出

我的答案

仙岛求药

输入格式

输出格式

样例输入1

样例输出1

样例输入2

样例输出2

样例输入3

样例输出3

我的答案

吃糖的时间

输入格式

输出格式

样例输入

样例输出

我的答案

奇怪的电梯

输入格式

输出格式

样例输入

样例输出

我的答案

密码锁

输入格式

输出格式

样例输入

样例输出

我的答案

奶酪

输入格式

输出格式

数据范围

样例输入

样例输出

样例解释

我的答案


一维坐标的移动

  • 时间限制:1000ms
  • 内存限制:131072K
  • 语言限制:C语言

在一个长度为 n 的坐标轴上,蒜头君想从 A 点 移动到 B 点。他的移动规则如下:

  1. 向前一步,坐标增加 1。
  2. 向后一步,坐标减少 1。
  3. 跳跃一步,使得坐标乘 2。

蒜头君不能移动到坐标小于 0 或大于 n 的位置。蒜头君想知道从 A 点移动到 B 点的最少步数是多少,你能帮他计算出来么?

输入格式

第一行输入三个整数 n,A,B,分别代表坐标轴长度,起始点坐标,终点坐标。(0≤A,B≤n≤5000)

输出格式

输出一个整数占一行,代表蒜头要走的最少步数。

格式说明

输出时每行末尾的多余空格,不影响答案正确性

样例输入
10 2 7
样例输出
3

我的答案

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXN 5005

int n, A, B;
int vis[MAXN];
int q[MAXN], head, tail;

void bfs() {
    head = tail = 0;
    q[tail++] = A;
    vis[A] = 1;
    while (head < tail) {
        int u = q[head++];
        if (u == B) {
            printf("%d\n", vis[u] - 1);
            return;
        }
        if (u + 1 <= n && !vis[u + 1]) {
            vis[u + 1] = vis[u] + 1;
            q[tail++] = u + 1;
        }
        if (u - 1 >= 0 && !vis[u - 1]) {
            vis[u - 1] = vis[u] + 1;
            q[tail++] = u - 1;
        }
        if (u * 2 <= n && !vis[u * 2]) {
            vis[u * 2] = vis[u] + 1;
            q[tail++] = u * 2;
        }
    }
}

int main() {
    scanf("%d%d%d", &n, &A, &B);
    bfs();
    return 0;
}

仙岛求药

  • 时间限制:1000ms
  • 内存限制:65536K
  • 语言限制:C语言

少年李逍遥的婶婶病了,王小虎介绍他去一趟仙灵岛,向仙女姐姐要仙丹救婶婶。叛逆但孝顺的李逍遥闯进了仙灵岛,克服了千险万难来到岛的中心,发现仙药摆在了迷阵的深处。迷阵由 M×N 个方格组成,有的方格内有可以瞬秒李逍遥的怪物,而有的方格内则是安全。现在李逍遥想尽快找到仙药,显然他应避开有怪物的方格,并经过最少的方格,而且那里会有神秘人物等待着他。现在要求你来帮助他实现这个目标。

输入格式

第一行输入两个非零整数 M 和 N,两者均不大于 20。M 表示迷阵行数, N 表示迷阵列数。

接下来有 M 行, 每行包含 N 个字符,不同字符分别代表不同含义:

1) '@':少年李逍遥所在的位置;2) '.':可以安全通行的方格;3) '#':有怪物的方格;4) '*':仙药所在位置。

输出格式

输出一行,该行包含李逍遥找到仙药需要穿过的最少的方格数目(计数包括初始位置的方块)。如果他不可能找到仙药, 则输出 −1。

格式说明

输出时每行末尾的多余空格,不影响答案正确性

样例输入1
8 8
.@##...#
#....#.#
#.#.##..
..#.###.
#.#...#.
..###.#.
...#.*..
.#...###
样例输出1
10
样例输入2
6 5
.*.#.
.#...
..##.
.....
.#...
....@
样例输出2
8
样例输入3
9 6
.#..#.
.#.*.#
.####.
..#...
..#...
..#...
..#...
#.@.##
.#..#.
样例输出3
-1

标程与题解:在迷宫上进行广度优先搜索,以@为起点,*为终点,#为障碍物。

#include <cstdio>
#include <iostream>
#include <string>
#include <queue>
using namespace std;
int M, N;
string maze[25];
bool vis[25][25];
int dir[4][2] = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}};
bool in(int x, int y) {
    return 0 <= x && x < M && 0 <= y && y < N;
}
struct node {
    int x, y, d;
    node(int _x, int _y, int _d) {
        x = _x;
        y = _y;
        d = _d;
    }
};
int bfs(int sx, int sy) {
    queue<node> q;
    q.push(node(sx, sy, 0));
    vis[sx][sy] = true;
    while (!q.empty()) {
        node now = q.front();
        q.pop();
        if (maze[now.x][now.y] == '*') {
            return now.d;
        }
        for (int i = 0; i < 4; i++) {
            int tx = now.x + dir[i][0];
            int ty = now.y + dir[i][1];
            if (in(tx, ty) && maze[tx][ty] != '#' && !vis[tx][ty]) {
                vis[tx][ty] = true;
                q.push(node(tx, ty, now.d + 1));
            }
        }
    }
    return -1;
}
int main() {
    freopen("seek.in", "r", stdin);
    freopen("seek.out", "w", stdout);
    cin >> M >> N;
    for (int i = 0; i < M; i++) {
        cin >> maze[i];
    }
    int x, y;
    for (int i = 0; i < M; i++) {
        for (int j = 0; j < N; j++) {
            if (maze[i][j] == '@') {
                x = i;
                y = j;
            }
        }
    }
    cout << bfs(x, y) << endl;
    return 0;
}

我的答案

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXN 25

int m, n;
char map[MAXN][MAXN];
int vis[MAXN][MAXN];
int q[MAXN * MAXN][2], head, tail;
int sx, sy, ex, ey;
int dx[4] = {0, 0, -1, 1};
int dy[4] = {-1, 1, 0, 0};

void bfs() {
    head = tail = 0;
    q[tail][0] = sx;
    q[tail][1] = sy;
    tail++;
    vis[sx][sy] = 1;
    while (head < tail) {
        int ux = q[head][0];
        int uy = q[head][1];
        head++;
        if (ux == ex && uy == ey) {
            printf("%d\n", vis[ux][uy] - 1);
            return;
        }
        for (int i = 0; i < 4; i++) {
            int vx = ux + dx[i];
            int vy = uy + dy[i];
            if (vx >= 0 && vx < m && vy >= 0 && vy < n && !vis[vx][vy] && map[vx][vy] != '#') {
                vis[vx][vy] = vis[ux][uy] + 1;
                q[tail][0] = vx;
                q[tail][1] = vy;
                tail++;
            }
        }
    }
    printf("-1\n");
}

int main() {
    scanf("%d%d", &m, &n);
    for (int i = 0; i < m; i++) {
        scanf("%s", map[i]);
        for (int j = 0; j < n; j++) {
            if (map[i][j] == '@') {
                sx = i;
                sy = j;
            } else if (map[i][j] == '*') {
                ex = i;
                ey = j;
            }
        }
    }
    bfs();
    return 0;
}

吃糖的时间

  • 时间限制:1000ms
  • 内存限制:65536K
  • 语言限制:C语言

童年的我们,将和朋友分享美好的食物作为自己的快乐。这天,C 小朋友得到了很多糖果,将要把这些糖果分给要好的朋友们。已知糖果从一个人传给另一个人需要 1 秒的时间,同一个小朋友不会重复接受糖果。

由于糖果足够多,如果某时刻某小朋友接受了糖果,他会将糖果分成若干份,同时分给那些在他身旁且还没有得到糖果的小朋友们,而且自己会吃一些糖果。由于嘴馋,小朋友们等不及将糖果发完,会在得到糖果后边吃边发。每个小朋友从接受糖果到吃完糖果需要 m 秒的时间。那么,如果第 1 秒 C 小朋友开始发糖,第多少秒所有小朋友都吃完了糖呢?

输入格式

输入第一行为三个数 n,p,c(1≤n,p≤100000),分别为小朋友数、关系数和 C 小朋友的编号。

第二行为一个数 m(m≤n×(n−1)/2​)),表示小朋友吃糖的时间。下面 p 行每行两个整数,表示某两个小朋友在彼此身旁。不会有同一个关系被描述多次的情况。

输出格式

输出一个数,为所有小朋友都吃完了糖的时间。

格式说明

输出时每行末尾的多余空格,不影响答案正确性

样例输入
4 3 1
2
1 2
2 3
1 4
样例输出
5

题解:BFS 搜出从起点到每个点的最短路,找到其中的最大值加上 m 即可。

我的答案

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXN 100005

typedef struct {
    int v, next;
} Edge;

Edge edge[MAXN << 1];
int head[MAXN], tot;
int n, p, c, m;
int dis[MAXN], vis[MAXN];
int q[MAXN], front, rear;

void add_edge(int u, int v) {
    edge[++tot].v = v;
    edge[tot].next = head[u];
    head[u] = tot;
}

void bfs() {
    memset(dis, 0x3f, sizeof(dis));
    dis[c] = 1;
    q[rear++] = c;
    vis[c] = 1;
    while (front != rear) {
        int u = q[front++];
        for (int i = head[u]; i; i = edge[i].next) {
            int v = edge[i].v;
            if (!vis[v]) {
                vis[v] = 1;
                dis[v] = dis[u] + 1;
                q[rear++] = v;
            }
        }
    }
}

int main() {
    scanf("%d%d%d", &n, &p, &c);
    scanf("%d", &m);
    for (int i = 1; i <= p; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        add_edge(u, v);
        add_edge(v, u);
    }
    bfs();
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        ans = ans > dis[i] ? ans : dis[i];
    }
    printf("%d\n", ans + m);
    return 0;
}

奇怪的电梯

  • 时间限制:1000ms
  • 内存限制:131072K
  • 语言限制:C语言

呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第 i 层楼 (1≤i≤N) 上有一个数字Ki​ (0≤Ki​≤N)。电梯只有四个按钮:开,关,上,下。上下的层数等于当前楼层上的那个数字。当然,如果不能满足要求,相应的按钮就会失灵。例如:3,3,1,2,5 代表了 Ki​(K1​=3,K2​=3,…),从 1 楼开始。在 1 楼,按“上”可以到 4 楼,按“下”是不起作用的,因为没有 −2楼。那么,从 A 楼到 B 楼至少要按几次按钮呢?

输入格式

第一行为 3 个用空格隔开的正整数,表示 N,A,B (1≤N≤200,1≤A,B≤N)。

第二行为 N 个用空格隔开的非负整数,表示 Ki​ (1≤Ki​≤100)。

输出格式

最少按键次数,若无法到达,则输出 −1。

格式说明

输出时每行末尾的多余空格,不影响答案正确性

样例输入
5 1 5
3 3 1 2 5
样例输出
3

标程与题解:使用 BFS,状态是当前所在的楼层,每次尝试按上下键,到达接下来的楼层。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
int K[205], dis[205];
queue<int> q;
int N, A, B;
void bfs(int A) {
    memset(dis, -1, sizeof(dis));
    dis[A] = 0;
    q.push(A);
    while (!q.empty()) {
        int now = q.front();
        q.pop();
        if (now - K[now] >= 1 && dis[now - K[now]] == -1) {
            dis[now - K[now]] = dis[now] + 1;
          q.push(now - K[now]);
        }
        if (now + K[now] <= N && dis[now + K[now]] == -1) {
            dis[now + K[now]] = dis[now] + 1;
            q.push(now + K[now]);
        }
    }
}
int main() {
    freopen("lift.in", "r", stdin);
    freopen("lift.out", "w", stdout);
    cin >> N >> A >> B;
    for (int i = 1; i <= N; i++) {
        cin >> K[i];
    }
    bfs(A);
    cout << dis[B] << endl;
    return 0;
}

我的答案

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXN 205

int n, a, b;
int k[MAXN];
int dis[MAXN], vis[MAXN];
int q[MAXN], front, rear;

void bfs() {
    memset(dis, 0x3f, sizeof(dis));
    dis[a] = 0;
    q[rear++] = a;
    vis[a] = 1;
    while (front != rear) {
        int u = q[front++];
        if (u + k[u] <= n && !vis[u + k[u]]) {
            vis[u + k[u]] = 1;
            dis[u + k[u]] = dis[u] + 1;
            q[rear++] = u + k[u];
        }
        if (u - k[u] >= 1 && !vis[u - k[u]]) {
            vis[u - k[u]] = 1;
            dis[u - k[u]] = dis[u] + 1;
            q[rear++] = u - k[u];
        }
    }
}

int main() {
    scanf("%d%d%d", &n, &a, &b);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &k[i]);
    }
    bfs();
    if (dis[b] == 0x3f3f3f3f) {
        printf("-1\n");
    } else {
        printf("%d\n", dis[b]);
    }
    return 0;
}

密码锁

  • 时间限制:1000ms
  • 内存限制:262144K
  • 语言限制:C语言

现在一个紧急的任务是打开一个密码锁。密码由四位数字组成,每个数字从 1 到 9 进行编号。每次可以对任何一位数字加 1 或减 1。当将9加 1 时,数字将变为1,当1减 1 的时,数字将变为9。你也可以交换相邻数字,每一个行动记做一步。现在你的任务是使用最小的步骤来打开锁。注意:最左边的数字不与最右边的数字相邻。

输入格式

第一行输入四位数字,表示密码锁的初始状态。

第二行输入四位数字,表示开锁的密码。

输出格式

输出一个整数,表示最小步骤。

格式说明

输出时每行末尾的多余空格,不影响答案正确性

样例输入
1234
2144
样例输出
2

标程与题解:此类题目是 BFS 最好的用武之地(最少的步骤),DFS 就不太方便了。

因为只是四位数,所以我们就可以把这个四位数当成状态,数组也开得下。

每次我们可以的操作有三种,第一种对于四位数字中的某一位加一,第二种对于四位数字中的某一位减一,第三种对于四位数字进行交换。

求出操作后的数,进行判断看是否需要入队。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
int dis[10005], digit[4];
queue<int> q;
int nxt(int x) {
    if (x == 9) {
        return 1;
    }
    return x + 1;
}
int pre(int x) {
    if (x == 1) {
        return 9;
    }
    return x - 1;
}
void divide(int x) {
    for (int i = 0; i < 4; i++) {
        digit[i] = x % 10;
        x /= 10;
    }
}
int get() {
    int ret = 0;
    for (int i = 3; i >= 0; i--) {
        ret = ret * 10 + digit[i];
    }
    return ret;
}
void bfs(int s) {
    memset(dis, -1, sizeof(dis));
    dis[s] = 0;
    q.push(s);
    while (!q.empty()) {
        int now = q.front();
        q.pop();
        divide(now);
        for (int i = 0; i < 4; i++) {
            digit[i] = nxt(digit[i]);
            int nt = get();
            if (dis[nt] == -1) {
                dis[nt] = dis[now] + 1;
                q.push(nt);
            }
            digit[i] = pre(digit[i]);
        }
        for (int i = 0; i < 4; i++) {
            digit[i] = pre(digit[i]);
            int nt = get();
            if (dis[nt] == -1) {
                dis[nt] = dis[now] + 1;
                q.push(nt);
            }
            digit[i] = nxt(digit[i]);
        }
        for (int i = 0; i < 3; i++) {
            swap(digit[i], digit[i + 1]);
            int nt = get();
            if (dis[nt] == -1) {
                dis[nt] = dis[now] + 1;
                q.push(nt);
            }
            swap(digit[i], digit[i + 1]);
        }
    }
}
int main() {
    freopen("lock.in", "r", stdin);
    freopen("lock.out", "w", stdout);
    int s, t;
    cin >> s >> t;
    bfs(s);
    cout << dis[t] << endl;
    return 0;
}

我的答案

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXN 10005

int s, t;
int dis[MAXN], vis[MAXN];
int q[MAXN], front, rear;

int get(int x, int i) {
    return x / (int)pow(10, i - 1) % 10;
}

int set(int x, int i, int v) {
    return x + (v - get(x, i)) * (int)pow(10, i - 1);
}

void bfs() {
    memset(dis, 0x3f, sizeof(dis));
    dis[s] = 0;
    q[rear++] = s;
    vis[s] = 1;
    while (front != rear) {
        int u = q[front++];
        for (int i = 1; i <= 4; i++) {
            int v = get(u, i);
            if (v == 9) {
                v = set(u, i, 1);
            } else {
                v = set(u, i, v + 1);
            }
            if (!vis[v]) {
                vis[v] = 1;
                dis[v] = dis[u] + 1;
                q[rear++] = v;
            }
            v = get(u, i);
            if (v == 1) {
                v = set(u, i, 9);
            } else {
                v = set(u, i, v - 1);
            }
            if (!vis[v]) {
                vis[v] = 1;
                dis[v] = dis[u] + 1;
                q[rear++] = v;
            }
        }
        for (int i = 2; i <= 4; i++) {
            int a = get(u, i - 1), b = get(u, i);
            int v = set(set(u, i - 1, b), i, a);
            if (!vis[v]) {
                vis[v] = 1;
                dis[v] = dis[u] + 1;
                q[rear++] = v;
            }
        }
    }
}

int main() {
    scanf("%d%d", &s, &t);
    bfs();
    printf("%d\n", dis[t]);
    return 0;
}

奶酪

  • 时间限制:1000ms
  • 内存限制:262144K
  • 语言限制:C语言

现有一块大奶酪,它的高度为 h,它的长度和宽度我们可以认为是无限大的,奶酪中间有许多 半径相同 的球形空洞。我们可以在这块奶酪中建立空间坐标系,在坐标系中,奶酪的下表面为 z=0,奶酪的上表面为 z=h。

现在,奶酪的下表面有一只小老鼠 Jerry,它知道奶酪中所有空洞的球心所在的坐标。如果两个空洞相切或是相交,则 Jerry 可以从其中一个空洞跑到另一个空洞,特别地,如果一个空洞与下表面相切或是相交,Jerry 则可以从奶酪下表面跑进空洞;如果一个空洞与上表面相切或是相交,Jerry 则可以从空洞跑到奶酪上表面。

位于奶酪下表面的 Jerry 想知道,在不破坏奶酪的情况下,最少经过多少个空洞才能够跑到奶酪的上表面去?

空间内两点 P1​(x,y,z),P2​(x,y,z) 的距离公式如下:dist(P1​,P2​)=√[(x1​−x2​)^2+(y1​−y2​)^2+(z1​−z2​)^2​]

输入格式

输入文件的第一行,包含一个正整数 T,代表该输入文件中所含的数据组数。

接下来是 T 组数据,每组数据的格式如下:

第一行包含三个正整数 n,h,r,两个数之间以一个空格分开,分别代表奶酪中空洞的数量,奶酪的高度和空洞的半径。

接下来的 n 行,每行包含三个整数 x,y,z,两个数之间以一个空格分开,表示空洞球心坐标为(x,y,z)。

输出格式

输出文件包含 T 行,分别对应 T 组数据的答案,如果在第 i 组数据中,Jerry 能从下表面跑到上表面,则输出需要经过的空洞数的最小值,如果不能,则输出-1

数据范围

对于 20% 的数据:n=1,1≤h,r≤10,000,坐标的绝对值不超过 10,000。

对于 40% 的数据:1≤n≤8,1≤h,r≤10,000,坐标的绝对值不超过 10,000。

对于 80% 的数据:1≤n≤1,000,1≤h,r≤10,000,坐标的绝对值不超过 10,000。

对于 100% 的数据:1≤n≤1,000,1≤h,r≤1,000,000,000,T≤20,坐标的绝对值不超过 1,000,000,000。

格式说明

输出时每行末尾的多余空格,不影响答案正确性

样例输入
3
2 4 1
0 0 1
0 0 3
2 5 1
0 0 1
0 0 4
2 5 2
0 0 2
2 0 4
样例输出
2
-1
2
样例解释

第一个空洞在 (0,0,0) 与下表面相切。

第二个空洞在 (0,0,4) 与上表面相切。

两个空洞在 (0,0,2) 相切。

输出2

第二组数据,由奶酪的剖面图可见:

两个空洞既不相交也不相切。

输出-1

第三组数据,由奶酪的剖面图可见:

两个空洞相交且与上下表面相切或相交。

输出2

标程与题解:所有高度小于等于 r 的空洞都可以作为起点,所有高度加 r 大于等于 h 的空洞都可以作为终点,一对圆心距离不超过 2r 的空洞是互相可达的。

建图后该题变成了多起点 BFS 问题,把起点在最开始全放入队列再进行搜索就好。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
long long x[1005], y[1005], z[1005];
bool f1[1005], f2[1005];
vector<int> G[1005];
int dis[1005];
queue<int> q;
int T, n, h, r;
int bfs() {
    memset(dis, -1, sizeof(dis));
    for (int i = 0; i < n; i++) {
        if (f1[i]) {
            dis[i] = 1;
            q.push(i);
        }
    }
    while (!q.empty()) {
        int now = q.front();
        q.pop();
        for (int i = 0; i < G[now].size(); i++) {
            int v = G[now][i];
            if (dis[v] == -1) {
                dis[v] = dis[now] + 1;
                q.push(v);
            }
        }
    }
    int ret = n + 1;
    for (int i = 0; i < n; i++) {
        if (f2[i] && dis[i] != -1) {
            ret = min(ret, dis[i]);
        }
    }
    if (ret == n + 1) {
        return -1;
    } else {
        return ret;
    }
}
int main() {
    freopen("cheese.in", "r", stdin);
    freopen("cheese.out", "w", stdout);
    cin >> T;
    while (T--) {
        cin >> n >> h >> r;
        for (int i = 0; i < n; i++) {
            cin >> x[i] >> y[i] >> z[i];
        }
        memset(f1, false, sizeof(f1));
        memset(f2, false, sizeof(f2));
        for (int i = 0; i < n; i++) {
            if (z[i] <= r) {
                f1[i] = true;
            }
            if (z[i] + r >= h) {
                f2[i] = true;
            }
        }
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                if ((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]) + (z[i] - z[j]) * (z[i] - z[j]) <= 4LL * r * r) {
                    G[i].push_back(j);
                    G[j].push_back(i);
                }
            }
        }
        cout << bfs() << endl;
        for (int i = 0; i < n; i++) {
            vector<int>().swap(G[i]);
        }
    }
    return 0;
}

我的答案

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stdbool.h>

#define MAXN 1010
#define INF 1e9

typedef struct {
    int x, y, z;
} Point;

int T, n, h, r;
Point holes[MAXN];
bool visited[MAXN];
bool adj_matrix[MAXN][MAXN];

double dist(Point p1, Point p2) {
    double dx = p1.x - p2.x;
    double dy = p1.y - p2.y;
    double dz = p1.z - p2.z;
    return sqrt(dx * dx + dy * dy + dz * dz);
}

int bfs() {
    int queue[MAXN], head = 0, tail = 0;
    int min_hole[MAXN];
    for (int i = 0; i < MAXN; i++) {
        min_hole[i] = INF;
    }

    for (int i = 0; i < n; i++) {
        if (holes[i].z - r <= 0) {
            visited[i] = true;
            queue[tail++] = i;
            min_hole[i] = 1;
        }
    }

    while (head < tail) {
        int cur = queue[head++];
        if (h - holes[cur].z - r <= 0) {
            return min_hole[cur];
        }

        for (int i = 0; i < n; i++) {
            if (!visited[i] && adj_matrix[cur][i]) {
                visited[i] = true;
                queue[tail++] = i;
                min_hole[i] = min_hole[cur] + 1;
            }
        }
    }

    return -1;
}

int main() {
    scanf("%d", &T);
    while (T--) {
        scanf("%d %d %d", &n, &h, &r);
        for (int i = 0; i < n; i++) {
            scanf("%d %d %d", &holes[i].x, &holes[i].y, &holes[i].z);
        }

        memset(adj_matrix, 0, sizeof(adj_matrix));
        memset(visited, 0, sizeof(visited));

        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                if (dist(holes[i], holes[j]) <= 2.0 * r) {
                    adj_matrix[i][j] = adj_matrix[j][i] = true;
                }
            }
        }

        printf("%d\n", bfs());
    }
    return 0;
}
  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在 Django ORM 中,可以使用一些特殊的查询条件来过滤日期和时间类型的数据。下面是一些常用的查询条件: 1. `date`:筛选出指定日期的数据。 示例代码: ``` from datetime import date from myapp.models import MyModel MyModel.objects.filter(date_field=date.today()) ``` 2. `time`:筛选出指定时间的数据。 示例代码: ``` from datetime import time from myapp.models import MyModel MyModel.objects.filter(time_field=time(hour=9, minute=0)) ``` 3. `year`:筛选出指定年份的数据。 示例代码: ``` from myapp.models import MyModel MyModel.objects.filter(date_field__year=2021) ``` 4. `month`:筛选出指定月份的数据。 示例代码: ``` from myapp.models import MyModel MyModel.objects.filter(date_field__month=9) ``` 5. `day`:筛选出指定日期的数据。 示例代码: ``` from myapp.models import MyModel MyModel.objects.filter(date_field__day=15) ``` 6. `week_day`:筛选出指定星期几的数据,星期一为1,星期天为7。 示例代码: ``` from myapp.models import MyModel MyModel.objects.filter(date_field__week_day=1) ``` 除了以上的查询条件,还可以使用 `__range` 来筛选一段时间范围内的数据。例如: ``` from datetime import date from myapp.models import MyModel start_date = date(2021, 9, 1) end_date = date(2021, 9, 30) MyModel.objects.filter(date_field__range=(start_date, end_date)) ``` 以上是一些常用的查询条件,更多查询条件可以查阅 Django 官方文档。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值