AtCoder Weekday Contest 0031 Beta题解(AWC 0031 Beta A-E)

A - Cooking Contest and Ingredients

【题目来源】

AtCoder:A - Cooking Contest and Ingredients

【题目描述】

Takahashi is serving as a judge for a cooking contest. \(N\) chefs are participating in this contest, and each chef is assigned a number from \(1\) to \(N\).
高桥正在担任一场烹饪比赛的评委。\(N\) 名厨师参加了这次比赛,每位厨师被分配了一个从 \(1\)\(N\) 的编号。

The contest uses \(M\) types of ingredients, numbered from \(1\) to \(M\). Chef \(i\) specializes in \(C_i\) types of ingredients, and the numbers of the ingredients they specialize in are \(T_{i,1}, T_{i,2}, \ldots, T_{i,C_i}\). When \(C_i = 0\), chef \(i\) has no ingredients they specialize in.
比赛使用 \(M\) 种食材,编号从 \(1\)\(M\)。厨师 \(i\) 擅长 \(C_i\) 种食材,他们擅长的食材编号为 \(T_{i,1}, T_{i,2}, \ldots, T_{i,C_i}\)。当 \(C_i = 0\) 时,厨师 \(i\) 没有擅长的食材。

As a result of the contest's preliminary round, chef \(i\) earned a score of \(V_i\). The \(N\) chefs are ranked according to the following rules, and the top \(K\) chefs (ranked \(1\)st through \(K\)th) advance to the finals.
在比赛的初赛结果中,厨师 \(i\) 获得了 \(V_i\) 分。\(N\) 名厨师按照以下规则排名,前 \(K\) 名厨师(排名第 1 到第 K 名)晋级决赛。

  • A chef with a higher score is ranked higher (i.e., has a smaller rank number).
    分数越高的厨师排名越高(即排名数字越小)。
  • Among chefs with the same score, the chef with the smaller chef number is ranked higher.
    在分数相同的厨师中,编号越小的厨师排名越高。

Under these rules, the ranking of all chefs is uniquely determined, and the \(K\) chefs who advance to the finals are also uniquely determined.
根据这些规则,所有厨师的排名是唯一确定的,晋级决赛的 \(K\) 名厨师也是唯一确定的。

In the finals, the \(K\) advancing chefs will cook dishes using only ingredients that all of them commonly specialize in. That is, an ingredient can be used in the finals only if all \(K\) chefs who advanced to the finals specialize in that ingredient.
在决赛中,晋级的 \(K\) 名厨师将只使用他们共同擅长的食材来烹饪菜肴。也就是说,只有在所有晋级决赛的 \(K\) 名厨师都擅长的食材才能用于决赛。

For Takahashi, find the number of ingredients that all \(K\) chefs advancing to the finals commonly specialize in. If there are no such ingredients, output \(0\).
为高桥求所有晋级决赛的 \(K\) 名厨师共同擅长的食材数量。如果没有这样的食材,输出 \(0\)

【输入】

\(N\) \(M\) \(K\)
\(V_1\) \(C_1\) \(T_{1,1}\) \(T_{1,2}\) \(\ldots\) \(T_{1,C_1}\)
\(V_2\) \(C_2\) \(T_{2,1}\) \(T_{2,2}\) \(\ldots\) \(T_{2,C_2}\)
\(\vdots\)
\(V_N\) \(C_N\) \(T_{N,1}\) \(T_{N,2}\) \(\ldots\) \(T_{N,C_N}\)

  • The first line contains the number of chefs \(N\), the number of ingredient types \(M\), and the number of finalists \(K\), separated by spaces.
  • In the following \(N\) lines, the \(i\)-th line (\(1 \leq i \leq N\)) first contains chef \(i\)'s score \(V_i\) and the number of ingredients \(C_i\) that chef \(i\) specializes in, separated by spaces. If \(C_i \geq 1\), the ingredient numbers \(T_{i,1}, T_{i,2}, \ldots, T_{i,C_i}\) follow on the same line, separated by spaces. If \(C_i = 0\), that line contains only the two values \(V_i\) and \(C_i\).

【输出】

Output on a single line the number of ingredients that all \(K\) chefs advancing to the finals commonly specialize in.

【输入样例】

3 5 2
100 3 1 2 3
80 4 1 2 4 5
90 2 1 2

【输出样例】

2

【代码详解】

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 100005;
int n, m, k, b[N];  // n: 选手数, m: 题目数, k: 获奖人数, b: 统计数组
struct Node
{
    int v, id, c;  // v: 分数, id: 编号, c: 题目数
    vector<int> t;  // 做对的题目列表
} a[N];

// 排序比较函数
bool cmp(Node a, Node b)
{
    if (a.v != b.v)  // 分数高的排前面
    {
        return a.v > b.v;
    }
    return a.id < b.id;  // 分数相同时,编号小的排前面
}
signed main()
{
    cin >> n >> m >> k;  // 选手数, 题目数, 获奖人数
    for (int i = 1; i <= n; i++)  // 输入选手信息
    {
        cin >> a[i].v;  // 分数
        cin >> a[i].c;  // 做对的题目数
        a[i].id = i;  // 编号
        for (int j = 1; j <= a[i].c; j++)  // 输入做对的题目
        {
            int x;
            cin >> x;
            a[i].t.push_back(x);
        }
    }
    sort(a + 1, a + n + 1, cmp);  // 按分数排序
    
    // 统计前k名做对的题目
    for (int i = 1; i <= k; i++)  // 遍历前k名选手
    {
        if (a[i].c == 0)  // 如果没有做对题目
        {
            continue;
        }
        for (int j = 0; j < a[i].t.size(); j++)  // 遍历做对的题目
        {
            b[a[i].t[j]]++;  // 统计题目被前k名做对的次数
        }
    }
    
    int cnt = 0;
    for (int i = 1; i <= m; i++)  // 统计每道题
    {
        if (b[i] == k)  // 如果这道题被所有前k名选手都做对了
        {
            cnt++;
        }
    }
    cout << cnt << endl;  // 输出结果
    return 0;
}

【运行结果】

3 5 2
100 3 1 2 3
80 4 1 2 4 5
90 2 1 2
2

B - Outstanding Score

【题目来源】

AtCoder:B - Outstanding Score

【题目描述】

Takahashi works in sports analytics. In a certain tournament, \(N\) players participated and competed over \(T\) rounds. Let \(S_{j,i}\) denote the score of player \(i\) (\(1 \leq i \leq N\)) in round \(j\) (\(1 \leq j \leq T\)).
高桥从事体育数据分析工作。在某个锦标赛中,\(N\) 名选手参加了 \(T\) 轮比赛。设 \(S_{j,i}\) 表示选手 \(i\)\(1 \leq i \leq N\))在第 \(j\) 轮(\(1 \leq j \leq T\))的得分。

Takahashi wants to identify rounds where a certain player overwhelmingly outperformed the others. Specifically, he defined a player being "outstanding" in a round as follows:
高桥希望找出某些选手在其中表现远超其他人的轮次。具体来说,他定义一个选手在某一轮"表现突出"如下:

> In round \(j\), let \(M_{j,i}\) be the maximum score among all players other than player \(i\). If \(S_{j,i} \geq 2 \times M_{j,i}\) holds, then player \(i\) is said to be "outstanding" in round \(j\).
在第 \(j\) 轮,设 \(M_{j,i}\) 为除选手 \(i\) 外所有选手中的最高得分。如果满足 \(S_{j,i} \geq 2 \times M_{j,i}\),则称选手 \(i\) 在第 \(j\) 轮"表现突出"。

Since all scores are at least \(1\), if player \(i\) is outstanding in round \(j\), then \(S_{j,i}\) is the maximum score in that round, and every other player's score is at most half of it. Therefore, there is at most one outstanding player in any single round.
由于所有得分至少为 \(1\),如果选手 \(i\) 在第 \(j\) 轮表现突出,则 \(S_{j,i}\) 是该轮的最高得分,且其他每位选手的得分至多为其一半。因此,在任何一轮中最多有一名表现突出的选手。

Determine the number of rounds, out of the \(T\) rounds, in which an outstanding player exists.
确定在 \(T\) 轮中,存在表现突出选手的轮数。

【输入】

\(N\) \(T\)
\(S_{1,1}\) \(S_{1,2}\) \(\ldots\) \(S_{1,N}\)
\(S_{2,1}\) \(S_{2,2}\) \(\ldots\) \(S_{2,N}\)
\(\vdots\)
\(S_{T,1}\) \(S_{T,2}\) \(\ldots\) \(S_{T,N}\)

  • The first line contains the number of players \(N\) and the number of rounds \(T\), separated by a space.
  • The following \(T\) lines, where the \(j\)-th line (\(1 \leq j \leq T\)) contains the scores \(S_{j,1}, S_{j,2}, \ldots, S_{j,N}\) of players \(1, 2, \ldots, N\) in round \(j\), separated by spaces.

【输出】

Print in one line the number of rounds, out of the \(T\) rounds, in which an outstanding player exists.

【输入样例】

3 4
10 3 4
5 6 5
1 1 3
7 4 4

【输出样例】

2

【代码详解】

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 100005;
int n, t;  // n: 每场比赛选手数, t: 比赛场数
int ans;  // 计数结果

signed main()
{
    cin >> n >> t;  // 输入每场人数和比赛场数
    for (int i = 1; i <= t; i++)  // 处理每场比赛
    {
        vector<int> s;  // 存储本场比赛的得分
        for (int i = 1; i <= n; i++)  // 输入每个选手的得分
        {
            int x;
            cin >> x;
            s.push_back(x);
        }
        sort(s.begin(), s.end(), greater<int>());  // 从大到小排序
        if (s[0] >= 2 * s[1])  // 判断最高分是否≥第二名的2倍
        {
            ans++;  // 满足条件,计数加1
        }
    }
    cout << ans << endl;  // 输出结果
    return 0;
}

【运行结果】

3 4
10 3 4
5 6 5
1 1 3
7 4 4
2

C - Island Hopping Adventure

【题目来源】

AtCoder:C - Island Hopping Adventure

【题目描述】

Takahashi is in a vast sea area dotted with \(N\) islands. The islands are numbered from \(1\) to \(N\), and island \(i\) is located at coordinates \((X_i, Y_i)\) on a two-dimensional plane.
高桥身处一片广阔的海域,海域中分布着 \(N\) 座岛屿。岛屿编号从 \(1\)\(N\),岛屿 \(i\) 位于二维平面上的坐标 \((X_i, Y_i)\) 处。

Takahashi travels from island to island using a small boat. From his current island, he can move to another island in one step if the Euclidean distance between them is at most \(D\). Here, the Euclidean distance between island \(i\) and island \(j\) is defined as \(\sqrt{(X_i - X_j)^2 + (Y_i - Y_j)^2}\). Note that he is allowed to revisit islands he has already visited.
高桥乘坐一艘小船在岛屿间航行。从当前所在岛屿出发,如果与另一座岛屿的欧几里得距离不超过 \(D\),他可以在一步内移动到该岛。这里,岛屿 \(i\) 和岛屿 \(j\) 之间的欧几里得距离定义为 \(\sqrt{(X_i - X_j)^2 + (Y_i - Y_j)^2}\)。注意,他允许重复访问已经访问过的岛屿。

Takahashi starts at island \(S\) and wants to reach island \(T\). Find the minimum number of moves required to travel from island \(S\) to island \(T\). If it is impossible to reach island \(T\), output \(-1\).
高桥从岛屿 \(S\) 出发,希望到达岛屿 \(T\)。求从岛屿 \(S\) 到岛屿 \(T\) 所需的最少移动次数。如果无法到达岛屿 \(T\),则输出 \(-1\)

【输入】

\(N\) \(D\) \(S\) \(T\)
\(X_1\) \(Y_1\)
\(X_2\) \(Y_2\)
\(\vdots\)
\(X_N\) \(Y_N\)

  • The first line contains \(N\) representing the number of islands, \(D\) representing the maximum distance that can be traveled in one move, \(S\) representing the number of the starting island, and \(T\) representing the number of the destination island, separated by spaces.
  • The following \(N\) lines give the coordinates of each island.
  • The \(i\)-th of these lines (\(1 \leq i \leq N\)) contains the \(x\)-coordinate \(X_i\) and \(y\)-coordinate \(Y_i\) of island \(i\), separated by a space.

【输出】

Output in one line the minimum number of moves required for Takahashi to travel from island \(S\) to island \(T\). If it is impossible to reach island \(T\), output \(-1\).

【输入样例】

5 3 1 5
0 0
2 1
-1 2
3 -1
4 3

【输出样例】

2

【代码详解】

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1505;
typedef pair<int, int> PII;
int n, d, S, T;  // n: 点数, d: 跳跃距离, S: 起点, T: 终点
int dist[N][N];  // 距离平方
struct Node
{
    int x, y;
} a[N];  // 坐标
bool vis[N];  // 访问标记

// 广度优先搜索
void bfs()
{
    queue<PII> q;  // 队列存储{节点, 步数}
    q.push({S, 0});  // 起点
    vis[S] = 1;
    while (!q.empty())
    {
        int u = q.front().first, step = q.front().second;
        q.pop();
        if (u == T)  // 到达终点
        {
            cout << step << endl;
            exit(0);  // 直接退出程序
        }
        for (int i = 1; i <= n; i++)  // 遍历所有点
        {
            if (!vis[i] && dist[u][i] <= d * d)  // 未访问且距离平方≤d²
            {
                vis[i] = 1;
                q.push({i, step + 1});  // 步数加1
            }
        }
    }
}

signed main()
{
    cin >> n >> d >> S >> T;  // 输入点数, 跳跃距离, 起点, 终点
    for (int i = 1; i <= n; i++)  // 输入坐标
    {
        cin >> a[i].x >> a[i].y;
    }
    
    // 预计算所有点对之间的距离平方
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            dist[i][j] = (a[i].x - a[j].x) * (a[i].x - a[j].x) + (a[i].y - a[j].y) * (a[i].y - a[j].y);
        }
    }
    
    bfs();  // BFS搜索
    cout << -1 << endl;  // 无法到达终点
    return 0;
}

【运行结果】

5 3 1 5
0 0
2 1
-1 2
3 -1
4 3
2

D - Library Inventory Check

【题目来源】

AtCoder:D - Library Inventory Check

【题目描述】

Takahashi is working as a librarian and is in charge of a book inspection spanning \(N\) days.
高桥是一名图书馆员,负责一项为期 \(N\) 天的书籍检查工作。

This library has \(M\) books. To ensure that no deterioration or damage to books is overlooked, a standard has been established that each book \(j\) \((1 \leq j \leq M)\) must be inspected on at least \(R_j\) days out of the \(N\) days.
这个图书馆有 \(M\) 本书。为了确保不遗漏书籍的劣化或损坏,制定了一个标准:每本书 \(j\)\(1 \leq j \leq M\))在 \(N\) 天中至少需要被检查 \(R_j\) 天。

On the other hand, the maximum number of books that can be inspected on day \(i\) \((1 \leq i \leq N)\) is \(L_i\). Also, the same book cannot be inspected multiple times on the same day, but the same book can be inspected again on a different day.
另一方面,每天 \(i\)\(1 \leq i \leq N\))最多可以检查 \(L_i\) 本书。此外,同一本书在同一天不能被检查多次,但同一本书可以在不同日期再次检查。

Takahashi is free to decide which books to inspect on which days. Determine whether it is possible to create an inspection plan that satisfies the inspection requirements for all books.
高桥可以自由决定在哪天检查哪些书。判断是否有可能制定一个满足所有书籍检查要求的检查计划。

Specifically, determine whether there exists an inspection plan that satisfies all of the following conditions:
具体来说,判断是否存在一个满足以下所有条件的检查计划:

  • The number of books inspected on each day \(i\) is at most \(L_i\).
    每天 \(i\) 检查的书籍数量不超过 \(L_i\)
  • The same book is not inspected more than once on the same day.
    同一本书在同一天不被检查超过一次。
  • The total number of days each book \(j\) is inspected is at least \(R_j\).
    每本书 \(j\) 被检查的总天数至少为 \(R_j\)

【输入】

\(N\) \(M\)
\(L_1\) \(L_2\) \(\ldots\) \(L_N\)
\(R_1\) \(R_2\) \(\ldots\) \(R_M\)

  • The first line contains \(N\), the number of days in the inspection period, and \(M\), the number of books, separated by a space.
  • The second line contains \(L_1, L_2, \ldots, L_N\), the maximum number of books that can be inspected on each day, separated by spaces.
  • The third line contains \(R_1, R_2, \ldots, R_M\), the required number of inspection days for each book, separated by spaces.

【输出】

If an inspection plan that satisfies the inspection requirements for all books exists, print Yes; otherwise, print No on a single line.

【输入样例】

3 4
2 3 2
1 2 1 2

【输出样例】

Yes

【解题思路】

image

【代码详解】

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 200005;

int n, m;
int l[N], r[N];  // l: 学生数组, r: 老师数组

signed main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        cin >> l[i];
    }
    for (int i = 1; i <= m; i++)
    {
        cin >> r[i];
    }
    
    sort(l + 1, l + n + 1);  // 对学生能力排序
    sort(r + 1, r + m + 1, greater<int>());  // 对老师要求降序排序

    int suml = 0, sumr = 0;  // suml: 学生总能力, sumr: 老师总要求
    
    for (int i = 1; i <= m; i++)  // 遍历老师
    {
        sumr += r[i];  // 累加老师要求
        
        // 查找第一个能力 >= i 的学生位置
        int pos = lower_bound(l + 1, l + n + 1, i) - l;
        // 能力 >= i 的学生数量
        suml += (n - (pos - 1));
        
        // 如果当前学生的总能力小于老师总要求
        if (suml < sumr)
        {
            cout << "No" << endl;
            return 0;
        }
    }
    cout << "Yes" << endl;
    return 0;
}

【运行结果】

3 4
2 3 2
1 2 1 2
Yes

E - Power Grid Blackout Crisis

【题目来源】

AtCoder:E - Power Grid Blackout Crisis

【题目描述】

Takahashi manages the power supply system of a certain region. This region has \(N\) factories and \(K\) power plants, which are connected by transmission lines forming a power transmission network.
高桥负责管理某地区的电力供应系统。该地区有 \(N\) 个工厂和 \(K\) 个发电厂,它们通过输电线路连接形成一个输电网络。

The locations are numbered from \(1\) to \(N + K\), where locations \(1\) through \(N\) correspond to factories, and locations \(N + 1\) through \(N + K\) correspond to power plants. Specifically, factory \(i\) (\(1 \leq i \leq N\)) is located at location \(i\), and power plant \(k\) (\(1 \leq k \leq K\)) is located at location \(N + k\).
地点编号从 \(1\)\(N + K\),其中地点 \(1\)\(N\) 对应工厂,地点 \(N + 1\)\(N + K\) 对应发电厂。具体来说,工厂 \(i\)\(1 \leq i \leq N\))位于地点 \(i\),发电厂 \(k\)\(1 \leq k \leq K\))位于地点 \(N + k\)

The transmission network consists of \(N + K\) locations connected by \(M\) transmission lines. Each transmission line \(j\) (\(1 \leq j \leq M\)) bidirectionally connects location \(U_j\) and location \(V_j\), and can transmit up to \(C_j\) megawatts of power per day. Specifically, letting \(f_j\) megawatts denote the amount of power flowing through transmission line \(j\) in the direction from location \(U_j\) to location \(V_j\), the constraint \(-C_j \leq f_j \leq C_j\) must be satisfied. Here, \(f_j > 0\) means power is transmitted from location \(U_j\) to location \(V_j\), and \(f_j < 0\) means power is transmitted from location \(V_j\) to location \(U_j\).
输电网络由 \(M\) 条输电线路连接 \(N + K\) 个地点构成。每条输电线路 \(j\)\(1 \leq j \leq M\))双向连接地点 \(U_j\) 和地点 \(V_j\),每天最多可传输 \(C_j\) 兆瓦的电力。具体来说,设 \(f_j\) 兆瓦为通过输电线路 \(j\) 从地点 \(U_j\) 流向地点 \(V_j\) 方向的功率,必须满足约束 \(-C_j \leq f_j \leq C_j\)。这里,\(f_j > 0\) 表示电力从地点 \(U_j\) 传输到地点 \(V_j\)\(f_j < 0\) 表示电力从地点 \(V_j\) 传输到地点 \(U_j\)

Each power plant \(k\) (\(1 \leq k \leq K\)), while operational, can supply any amount of power between \(0\) and \(W_k\) megawatts per day. Each factory \(i\) (\(1 \leq i \leq N\)) needs to receive at least \(B_i\) megawatts of power per day to operate. A factory may receive more than \(B_i\) megawatts of power; it operates without issues even if surplus power flows in.
每个发电厂 \(k\)\(1 \leq k \leq K\))在运行时,每天可供应 \(0\)\(W_k\) 兆瓦之间的任意电量。每个工厂 \(i\)\(1 \leq i \leq N\))每天需要接收至少 \(B_i\) 兆瓦的电力才能运营。工厂可以接收超过 \(B_i\) 兆瓦的电力;即使有盈余电力流入,工厂也能正常运行。

At each location, flow conservation must hold for the power balance. The net inflow \(\mathrm{net}(v)\) at location \(v\) is defined as follows:
在每个地点,电力平衡必须满足流量守恒。地点 \(v\)净流入 \(\mathrm{net}(v)\) 定义如下:

\(\mathrm{net}(v) = \sum_{\substack{j :\, V_j = v}} f_j - \sum_{\substack{j :\, U_j = v}} f_j\)

To clarify the meaning of this formula: for transmission line \(j\), when \(f_j > 0\), power flows from \(U_j\) to \(V_j\), so \(f_j\) flows into location \(V_j\) and \(f_j\) flows out of location \(U_j\). When \(f_j < 0\), the reverse holds. \(\mathrm{net}(v)\) equals the total inflow to location \(v\) minus the total outflow from location \(v\), summed over all transmission lines connected to location \(v\).
为澄清此公式的含义:对于输电线路 \(j\),当 \(f_j > 0\) 时,电力从 \(U_j\) 流向 \(V_j\),因此 \(f_j\) 流入地点 \(V_j\)\(f_j\) 流出地点 \(U_j\)。当 \(f_j < 0\) 时,情况相反。\(\mathrm{net}(v)\) 等于流入地点 \(v\) 的总流量减去流出地点 \(v\) 的总流量,对连接到地点 \(v\) 的所有输电线路求和。

The following conditions must be satisfied at each location:
每个地点必须满足以下条件:

  • If location \(v\) is factory \(i\): \(\mathrm{net}(v) \geq B_i\). That is, a net inflow of at least \(B_i\) megawatts must flow into factory \(i\) through the transmission lines.
    如果地点 \(v\) 是工厂 \(i\)\(\mathrm{net}(v) \geq B_i\)。也就是说,通过输电线路流入工厂 \(i\) 的净流入必须至少为 \(B_i\) 兆瓦。
  • If location \(v\) is an operational power plant \(k\): \(-W_k \leq \mathrm{net}(v) \leq 0\). That is, power plant \(k\) can supply between \(0\) and \(W_k\) megawatts of power. Since the supplied power leaves the location, the net inflow is non-positive.
    如果地点 \(v\)运行中的发电厂 \(k\)\(-W_k \leq \mathrm{net}(v) \leq 0\)。也就是说,发电厂 \(k\) 可供应 \(0\)\(W_k\) 兆瓦的电力。由于供应的电力会离开该地点,净流入为非正。
  • If location \(v\) is a non-operational power plant: \(\mathrm{net}(v) = 0\). It cannot supply power, but as long as inflow equals outflow, it can still function as a relay point through which power passes via transmission lines.
    如果地点 \(v\)非运行的发电厂:\(\mathrm{net}(v) = 0\)。它不能供应电力,但只要流入等于流出,它仍可作为电力通过输电线路传递的中继点。

Initially, all \(K\) power plants are operational, but it is not guaranteed that all factories can secure the necessary power even in the initial state.
初始时,所有 \(K\) 个发电厂都在运行,但无法保证即使在初始状态下所有工厂都能获得必要的电力。

However, due to aging, power plants are expected to fail and shut down sequentially. Specifically, \(Q\) events occur in order. At each event \(t\) (\(1 \leq t \leq Q\)), power plant \(S_t\) fails and becomes non-operational. Once a power plant fails, it remains non-operational permanently. Note that \(Q \leq K\), and not all power plants necessarily fail.
然而,由于老化,发电厂预计会依次故障并停机。具体来说,按顺序发生 \(Q\) 个事件。在每个事件 \(t\)\(1 \leq t \leq Q\)),发电厂 \(S_t\) 发生故障并变为非运行。一旦发电厂故障,它将永久保持非运行状态。注意,\(Q \leq K\),且并非所有发电厂都必然故障。

For the state immediately after each event occurs, determine whether all factories can secure the necessary power and continue operating. That is, after each event, answer whether there exists a way to route power such that, using only the currently operational power plants, the flow conservation conditions are satisfied and at least \(B_i\) megawatts of power is delivered to each factory \(i\).
对于每个事件发生后的即时状态,判断所有工厂是否能够获得必要的电力并继续运营。也就是说,在每个事件后,回答是否存在一种电力路由方式,使得仅使用当前运行的发电厂,满足流量守恒条件,并且每个工厂 \(i\) 获得至少 \(B_i\) 兆瓦的电力。

【输入】

\(N\) \(K\) \(M\)
\(B_1\) \(B_2\) \(\ldots\) \(B_N\)
\(W_1\) \(W_2\) \(\ldots\) \(W_K\)
\(U_1\) \(V_1\) \(C_1\)
\(U_2\) \(V_2\) \(C_2\)
\(\vdots\)
\(U_M\) \(V_M\) \(C_M\)
\(Q\)
\(S_1\)
\(S_2\)
\(\vdots\)
\(S_Q\)

  • The first line contains the number of factories \(N\), the number of power plants \(K\), and the number of transmission lines \(M\), separated by spaces.
  • The second line contains the daily power requirements \(B_1, B_2, \ldots, B_N\) of each factory, separated by spaces. Factory \(i\) corresponds to location \(i\).
  • The third line contains the maximum daily supply \(W_1, W_2, \ldots, W_K\) of each power plant, separated by spaces. Power plant \(k\) corresponds to location \(N + k\).
  • The following \(M\) lines, where the \(j\)-th line (\(1 \leq j \leq M\)), contains the locations \(U_j\), \(V_j\) connected by transmission line \(j\), and the maximum transmission capacity \(C_j\), separated by spaces. Each transmission line is bidirectional (undirected edge), and is given with \(U_j < V_j\).
  • The next line contains the number of events \(Q\).
  • The following \(Q\) lines, where the \(t\)-th line (\(1 \leq t \leq Q\)), contains the number \(S_t\) (\(1 \leq S_t \leq K\)) of the power plant that fails in event \(t\). Power plant \(S_t\) corresponds to location \(N + S_t\).

【输出】

Output \(Q\) lines. The \(t\)-th line (\(1 \leq t \leq Q\)) should contain Yes if all factories can secure the necessary power immediately after event \(t\) occurs, and No otherwise.

【输入样例】

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

【输出样例】

Yes
No

【解题思路】

image

【代码详解】

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 100, M = 1000;

int n, k, m, q;
int B[N], W[N], S[N];  // B: 需求, W: 供应, S: 要移除的供应商
int h[N], e[M], w[M], ne[M], idx = 2;  // 网络流相关数组
int d[N], cur[N];
bool alive[N];  // 标记供应商是否存活
int ss, tt;  // 超级源点和超级汇点
struct Edge
{
    int u, v, c;
} edges[M];  // 存储原图中的边

// 添加网络流边
void add(int a, int b, int c)
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}

// BFS构建层次图
bool bfs()
{
    memset(d, 0, sizeof(d));
    queue<int> q;
    q.push(ss);
    d[ss] = 1;
    while (q.size())
    {
        int u = q.front();
        q.pop();
        for (int i = h[u]; i != -1; i = ne[i])
        {
            int v = e[i];
            if (d[v] == 0 && w[i])  // 如果未访问且边有容量
            {
                d[v] = d[u] + 1;
                q.push(v);
                if (v == tt)
                {
                    return true;  // 到达汇点
                }
            }
        }
    }
    return false;  // 无法到达汇点
}

// DFS进行多路增广
int dfs(int u, int mf)
{
    if (u == tt)
    {
        return mf;  // 到达汇点
    }
    int sum = 0;
    for (int i = cur[u]; i != -1; i = ne[i])
    {
        cur[u] = i;  // 当前弧优化
        int v = e[i];
        if (d[v] == d[u] + 1 && w[i])  // 满足层次关系和容量限制
        {
            int f = dfs(v, min(mf, w[i]));
            w[i] -= f;     // 正向边减少容量
            w[i ^ 1] += f; // 反向边增加容量
            sum += f;
            mf -= f;
            if (mf == 0)
            {
                break;  // 流量已用完
            }
        }
    }
    if (sum == 0)
    {
        d[u] = 0;  // 残量网络中u不可达
    }
    return sum;
}

// Dinic算法计算最大流
int dinic()
{
    int flow = 0;
    while (bfs())  // 每次构建新的层次图
    {
        memcpy(cur, h, sizeof(h));  // 重置当前弧
        flow += dfs(ss, 1e18);
    }
    return flow;
}

signed main()
{
    cin >> n >> k >> m;
    int need = 0;  // 总需求量
    for (int i = 1; i <= n; i++)
    {
        cin >> B[i];
        need += B[i];  // 累加总需求
    }
    for (int i = 1; i <= k; i++)
    {
        cin >> W[i];
    }
    for (int i = 1; i <= m; i++)
    {
        cin >> edges[i].u >> edges[i].v >> edges[i].c;  // 读取原图中的边
    }
    cin >> q;
    for (int i = 1; i <= q; i++)
    {
        cin >> S[i];  // 读取要移除的供应商
    }
    memset(alive, true, sizeof(alive));  // 初始化所有供应商为存活状态
    
    // 处理每个查询
    for (int i = 1; i <= q; i++)
    {
        alive[S[i]] = false;  // 标记该供应商为移除状态
        
        // 重新建图
        memset(h, -1, sizeof(h));
        idx = 2;
        ss = 0, tt = n + k + 1;  // 超级源点和超级汇点
        
        // 连接任务到汇点
        for (int i = 1; i <= n; i++)
        {
            add(i, tt, B[i]);  // 任务i到汇点,容量为需求量
            add(tt, i, 0);     // 反向边
        }
        
        // 连接源点到存活的供应商
        for (int i = 1; i <= k; i++)
        {
            if (alive[i])
            {
                add(ss, n + i, W[i]);  // 源点到供应商,容量为供应量
                add(n + i, ss, 0);     // 反向边
            }
        }
        
        // 添加原始图中的边(双向容量)
        for (int i = 1; i <= m; i++)
        {
            int u = edges[i].u, v = edges[i].v, c = edges[i].c;
            add(u, v, c);
            add(v, u, 0);
            add(v, u, c);
            add(u, v, 0);
        }
        
        int flow = dinic();  // 计算最大流
        if (flow >= need)    // 检查是否满足所有需求
        {
            cout << "Yes" << endl;
        }
        else
        {
            cout << "No" << endl;
        }
    }
    return 0;
}

【运行结果】

2 2 3
2 3
2 5
1 3 2
1 4 2
2 4 3
2
1
Yes
2
No
posted @ 2026-03-24 10:54  团爸讲算法  阅读(3)  评论(0)    收藏  举报