Cocoicobird
热爱永远可以成为你继续下去的理由

今日刷题:\(1019-1022\)

1019 NC25020 [USACO 2007 Nov S]Cow Hurdles

题目描述

Farmer John wants the cows to prepare for the county jumping competition, so Bessie and the gang are practicing jumping over hurdles. They are getting tired, though, so they want to be able to use as little energy as possible to jump over the hurdles.
Obviously, it is not very difficult for a cow to jump over several very short hurdles, but one tall hurdle can be very stressful. Thus, the cows are only concerned about the height of the tallest hurdle they have to jump over.
The cows' practice room has \(N\) (\(1 ≤ N ≤ 300\)) stations, conveniently labeled \(1..N\). A set of \(M\) (\(1 ≤ M ≤ 25,000\)) one-way paths connects pairs of stations; the paths are also conveniently labeled \(1..M\). Path \(i\) travels from station \(S_i\) to station \(E_i\) and contains exactly one hurdle of height \(H_i\) (\(1 ≤ H_i ≤ 1,000,000\)). Cows must jump hurdles in any path they traverse.
The cows have \(T\) (\(1 ≤ T ≤ 40,000\)) tasks to complete. Task \(i\) comprises two distinct numbers, \(A_i\) and \(B_i\) (\(1 ≤ A_i ≤ N; 1 ≤ B_i ≤ N\)), which connote that a cow has to travel from station \(A_i\) to station Bi (by traversing over one or more paths over some route). The cows want to take a path the minimizes the height of the tallest hurdle they jump over when traveling from \(A_i\) to \(B_i\) . Your job is to write a program that determines the path whose tallest hurdle is smallest and report that height.

输入描述
  • Line \(1\): Three space-separated integers: \(N, M\), and \(T\)
  • Lines \(2..M+1\): Line \(i+1\) contains three space-separated integers: \(S_i\), \(E_i\), and \(H_i\)
  • Lines \(M+2..M+T+1\): Line \(i+M+1\) contains two space-separated integers that describe task \(i\): \(A_i\) and \(B_i\)
输出描述
  • Lines \(1..T\): Line \(i\) contains the result for task \(i\) and tells the smallest possible maximum height necessary to travel between the stations. Output \(-1\) if it is impossible to travel between the two stations.
示例

输入

5 6 3
1 2 12
3 2 8
1 3 5
2 5 3
3 4 4
2 4 8
3 4
1 2
5 1

输出

4
8
-1

说明
Query \(1\): The best way is to simply travel on the path from station \(3\) to station \(4\).
Query \(2\): There is a path from station \(1\) to station \(2\), but a better way would be to travel from station \(1\) to station \(3\) and then to station \(2\).
Query \(3\): There are no paths that start at station \(5\), so it is clear that there is no way to reach station \(1\) from station \(5\).

解题思路

\(Floyd\) 算法,俩点间的代价为所有路径上最大高度的最小值。

C++代码
#include <bits/stdc++.h>
using namespace std;
const int N = 310;

int n, m, T;
int g[N][N];

int main() {
    memset(g, 0x3f, sizeof g);
    scanf("%d%d%d", &n, &m, &T);
    for (int i = 0; i < m; i++) {
        int s, e, h;
        scanf("%d%d%d", &s, &e, &h);
        g[s][e] = h;
    }
    for (int k = 1; k <= n; k++)
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                if (i != k && k != j)
                    g[i][j] = min(max(g[i][k], g[k][j]), g[i][j]);
    for (int i = 0; i < T; i++) {
        int a, b;
        scanf("%d%d", &a, &b);
        if (g[a][b] == 0x3f3f3f3f)
            g[a][b] = -1;
        printf("%d\n", g[a][b]);
    }
    return 0;
}

1020 NC208246 胖胖的牛牛

题目描述

每逢佳节胖三斤,牛牛在过去的节日里长胖了,连拐弯都困难,甚至会卡在门上,所以他很讨厌拐弯。给你一个 \(N*N\)\(2≤N≤100\))的方格中,x 表示障碍,. 表示没有障碍(可以走),牛牛可以从一个格子走到他相邻的四个格子,但是不能走出这些格子。问牛牛从 \(A\) 点到 \(B\) 点最少需要转 \(90\) 度的弯几次。

输入描述

第一行一个整数:\(N\),下面 \(N\) 行,每行 \(N\) 个字符,只出现字符:.xAB;表示上面所说的矩阵格子,每个字符后有一个空格。

输出描述

一个整数:最少转弯次数。如果不能到达,输出 \(-1\)

示例

输入

3
. x A
. . .
B x .

输出

2
备注

开始和结束时的方向任意。

解题思路

\(BFS\)。从起点往四个方向遍历周边四个格子,如果方向转变为 \(90\) 度,则改变次数加一,也就是两次方向奇偶性不同。起始方向任意,转向次数为 \(0\),最后如果可达,答案减一即可。

C++代码
// NC208246
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, -1, 0, 1};

int n, ans = 1e9;
bool vis[N][N];
char g[N][N];
pair<int, int> st, ed;

struct Node {
    int x, y, cnt, d;
    bool operator> (const Node &n) const {
        return cnt > n.cnt;
    }
};

void bfs() {
    priority_queue<Node, vector<Node>, greater<Node>> pq;
    pq.push({st.first, st.second, 0, -1});
    while (pq.size()) {
        auto t = pq.top();
        pq.pop();
        if (t.x == ed.first && t.y == ed.second) {
            ans = min(ans, t.cnt);
            break;
        }
        vis[t.x][t.y] = true;
        // printf("%d %d %d %d\n", t.x, t.y, t.cnt, t.d);
        for (int i = 0; i < 4; i++) {
            int a = t.x + dx[i], b = t.y + dy[i];
            if (a >= 1 && a <= n && b >= 1 && b <= n && !vis[a][b] && g[a][b] != 'x') {
                int cnt = t.cnt + ((t.d == -1) || (i & 1) != (t.d & 1));
                pq.push({a, b, cnt, i});
            }
        }
    }
    if (ans == 1e9)
        ans = -1;
    else
        ans -= 1;
}

int main() {
    cin >> n;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            cin >> g[i][j];
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++) {
            if (g[i][j] == 'A')
                st = {i, j};
            else if (g[i][j] == 'B')
                ed = {i, j};
        }
    bfs();
    printf("%d\n", ans);
    return 0;
}

1021 NC212331 ObstacleCourse障碍训练课

题目描述

考虑一个 \(N \times N\) (\(1 <= N <= 100\)) 的有 \(1\) 个个方格组成的正方形牧场。有些方格是奶牛们不能踏上的,它们被标记为了 x。例如下图:

. . B x .
. x x A .
. . . x .
. x . . .
. . x . .

贝茜发现自己恰好在点 \(A\) 处,她想去 \(B\) 处的盐块舔盐。缓慢而且笨拙的动物,比如奶牛,十分讨厌转弯。尽管如此,当然在必要的时候她们还是会转弯的。对于一个给定的牧场,请你计算从 \(A\)\(B\) 最少的转弯次数。开始的时候,贝茜可以使面对任意一个方向。贝茜知道她一定可以到达。

输入描述

\(1\) 行: 一个整数 \(N\)
\(2..N + 1\): 行 \(i+1\)\(N\) 个字符 (., x, A, B),表示每个点的状态。

输出描述

\(1\): 一个整数,最少的转弯次数。

示例

输入

3
.xA
…
Bx.

输出

2
解题思路

思路类似上一题,但是在当前方向,能走多远走多远,否则每次只走一格,到某一点的转向次数不会更优。

C++代码
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, -1, 0, 1};

int n, ans = 1e9;
bool vis[N][N];
char g[N][N];
pair<int, int> st, ed;

struct Node {
    int x, y, cnt, d;
    bool operator> (const Node &n) const {
        return cnt > n.cnt;
    }
};

void bfs() {
    priority_queue<Node, vector<Node>, greater<Node>> pq;
    pq.push({st.first, st.second, 0, -1});
    while (pq.size()) {
        auto t = pq.top();
        pq.pop();
        if (t.x == ed.first && t.y == ed.second) {
            ans = min(ans, t.cnt);
            break;
        }
        vis[t.x][t.y] = true;
        // printf("%d %d %d %d\n", t.x, t.y, t.cnt, t.d);
        for (int i = 0; i < 4; i++) {
            for (int j = 1; ; j++) {
            int a = t.x + dx[i] * j, b = t.y + dy[i] * j;
                if (a >= 1 && a <= n && b >= 1 && b <= n && !vis[a][b] && g[a][b] != 'x') {
                    int cnt = t.cnt + (t.d != i);
                    pq.push({a, b, cnt, i});
                } else
                    break;
            }
        }
    }
    if (ans == 1e9)
        ans = -1;
    else
        ans -= 1;
}

int main() {
    cin >> n;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            cin >> g[i][j];
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++) {
            if (g[i][j] == 'A')
                st = {i, j};
            else if (g[i][j] == 'B')
                ed = {i, j};
        }
    bfs();
    printf("%d\n", ans);
    return 0;
}

1022 NC251589 Meeting

题目描述

Bessie and her friend Elsie decide to have a meeting. However, after Farmer John decorated his
fences they were separated into different blocks. John's farm are divided into n blocks labelled from \(1\) to \(n\).
Bessie lives in the first block while Elsie lives in the \(n\)-th one. They have a map of the farm which shows that it takes they \(t_i\) minutes to travel from a block in \(E_i\) to another block
in \(E_i\) where \(E_i (1≤i≤m)\) is a set of blocks. They want to know how soon they can meet each other and which block should be chosen to have the meeting.

输入描述

The first line contains an integer \(T (1≤T≤6)\), the number of test cases. Then \(T\) test cases follow.
The first line of input contains \(n\) and \(m\). \(2≤n≤10^5\). The following \(m\) lines describe the sets \(E_i (1≤i≤m)\). Each line will contain two integers \(t_i(1≤t_i≤10^9)\) and \(S_i (S_i>0)\) firstly. Then \(S_i\) integer follows which are the labels of blocks in \(E_i\). It is guaranteed that \(∑S_i≤10^6\).

输出描述

For each test case, if they cannot have the meeting, then output Evil John (without quotes) in one line.
Otherwise, output two lines. The first line contains an integer, the time it takes for they to meet.
The second line contains the numbers of blocks where they meet. If there are multiple optional blocks, output all of them in ascending order.

示例

输入

2
5 4
1 3 1 2 3
2 2 3 4
10 2 1 5
3 3 3 4 5
3 1
1 2 1 2

输出

Case #1: 3
3 4
Case #2: Evil John
备注

UVALive7250 / hduoj 5521

解题思路

\(n\) 个点,\(m\) 个块,每个块内部若干点,其内部的点两两相接且距离相同,即每个块内部都是一个完全图,且所有边权值相同。如果直接建立完全图,时间和空间复杂度都不符合要求。引入虚拟点,每个块对应一个虚拟点,每个块内部的点到虚拟点的距离为 \(0\),而虚拟点到每个块内部的点的距离为题目中对应的权值,这样就只需要建立 \(2*(n+m)\) 个边。
建图完成之后,从 \(1\) 开始和从 \(n\) 开始分别运行一遍 \(Dijkstra\) 算法,找出答案,然后确定答案对应的点。

C++代码
// NC251589
#include <bits/stdc++.h>
using namespace std;
const int N = 200010, M = 2000010;
typedef long long LL;
const LL INF = 0x3f3f3f3f3f3f3f3f;

int T, n, m;
int h[N], e[M], ne[M], w[M], idx;
bool st[N];
LL dist1[N], distn[N];

void add(int a, int b, int c) {
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}

void dijkstra(int s, LL dist[]) {
    memset(st, false, sizeof st);
    for (int i = 1; i < N; i++)
        dist[i] = INF;
    priority_queue<pair<LL, int>, vector<pair<LL, int>>, greater<pair<LL, int>>> pq;
    dist[s] = 0;
    pq.push({dist[s], s});
    while (pq.size()) {
        auto t = pq.top();
        pq.pop();
        int ver = t.second;
        if (st[ver])
            continue;
        st[ver] = true;
        for (int i = h[ver]; ~i; i = ne[i]) {
            int j = e[i];
            // cout << ver << ' ' << j << ' ' << dist[j] << ' ' << dist[ver] << ' ' << (LL) w[i] << endl;
            if (dist[j] > dist[ver] + (LL) w[i]) {
                dist[j] = dist[ver] + (LL) w[i];
                pq.push({dist[j], j});
            }
        }
    }
}

int main() {
    scanf("%d", &T);
    for (int k = 1; k <= T; k++) {
        memset(h, -1, sizeof h);
        idx = 0;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= m; i++) {
            int t, s;
            scanf("%d%d", &t, &s);
            for (int j = 1; j <= s; j++) {
                int ver;
                scanf("%d", &ver);
                add(ver, i + n, 0);
                add(i + n, ver, t);
            }
        }
        dijkstra(1, dist1);
        if (dist1[n] == INF) {
            printf("Case #%d: Evil John\n", k);
            continue;
        }
        dijkstra(n, distn);
        LL res = INF;
        for (int i = 1; i <= n; i++) {
            // cout << res << ' ' << dist1[i] << ' ' << distn[i] << endl;
            res = min(res, max(dist1[i], distn[i]));
        }
        printf("Case #%d: %lld\n", k, res);
        for (int i = 1; i <= n; i++) {
            if (res == max(dist1[i], distn[i]))
                printf("%d ", i);
        }
        printf("\n");
    }
    return 0;
}
posted on 2026-03-20 10:39  Cocoicobird  阅读(2)  评论(0)    收藏  举报