|
| 1 | +# Cycle Detection in a Directed Graph |
| 2 | + |
| 3 | +| | | |
| 4 | +| :--- | :--- | |
| 5 | +| **Input** | Standard input | |
| 6 | +| **Output** | Standard output | |
| 7 | + |
| 8 | +### Problem Statement |
| 9 | +Given a directed graph, determine whether it contains at least one **cycle**. |
| 10 | + |
| 11 | +### Input Format |
| 12 | +- The first line contains the number of vertices $N$ ($N \le 50$). |
| 13 | +- The following $N$ lines each contain $N$ integers (0 or 1), representing the adjacency matrix. |
| 14 | +- The $j$-th number in the $i$-th row is `1` if there is a directed edge from vertex $i$ to vertex $j$. |
| 15 | +- It is guaranteed that the main diagonal of the matrix contains only zeros. |
| 16 | + |
| 17 | +### Output Format |
| 18 | +Print `1` if the graph contains at least one cycle, and `0` otherwise. |
| 19 | + |
| 20 | +### Examples |
| 21 | +| Input | Output | |
| 22 | +| :--- | :--- | |
| 23 | +| `3` <br> `0 1 0` <br> `0 0 1` <br> `0 0 0` | `0` | |
| 24 | + |
| 25 | +#include <iostream> |
| 26 | +using namespace std; |
| 27 | + |
| 28 | +int n; |
| 29 | +int m[50][50]; |
| 30 | +int color[50]; |
| 31 | +int found = 0; |
| 32 | + |
| 33 | +void dfs(int v) { |
| 34 | + color[v] = 1; |
| 35 | + |
| 36 | + for (int u = 0; u < n; u++) { |
| 37 | + if (m[v][u] == 1) { |
| 38 | + if (color[u] == 1) { |
| 39 | + found = 1; |
| 40 | + return; |
| 41 | + } |
| 42 | + if (color[u] == 0) { |
| 43 | + dfs(u); |
| 44 | + if (found) |
| 45 | + return; |
| 46 | + } |
| 47 | + } |
| 48 | + } |
| 49 | + |
| 50 | + color[v] = 2; |
| 51 | +} |
| 52 | + |
| 53 | +int main() { |
| 54 | + cin >> n; |
| 55 | + |
| 56 | + for (int i = 0; i < n; i++) { |
| 57 | + for (int j = 0; j < n; j++) { |
| 58 | + cin >> m[i][j]; |
| 59 | + } |
| 60 | + } |
| 61 | + |
| 62 | + for (int i = 0; i < n; i++) { |
| 63 | + color[i] = 0; |
| 64 | + } |
| 65 | + |
| 66 | + for (int i = 0; i < n; i++) { |
| 67 | + if (color[i] == 0) { |
| 68 | + dfs(i); |
| 69 | + if (found) { |
| 70 | + cout << 1; |
| 71 | + return 0; |
| 72 | + } |
| 73 | + } |
| 74 | + } |
| 75 | + |
| 76 | + cout << 0; |
| 77 | + return 0; |
| 78 | +} |
| 79 | + |
| 80 | + |
| 81 | +# 1. Cheat Detection (Детекция списывания) |
| 82 | + |
| 83 | +| | | |
| 84 | +| :--- | :--- | |
| 85 | +| **Input** | Standard input | |
| 86 | +| **Output** | Standard output | |
| 87 | + |
| 88 | +### Problem Statement |
| 89 | +The "MSHP" (Moscow School of Programming) is developing an innovative cheat detection algorithm. One module of this algorithm needs to determine if it is possible to divide the students in a class into **two groups**: those who cheat ("borrowers") and those who provide the answers ("helpers"). |
| 90 | + |
| 91 | +You are given all pairs of students who exchanged suspicious messages. Determine if the students can be split into two groups such that every message exchange occurred between students from **different** groups. |
| 92 | + |
| 93 | +### Input Format |
| 94 | +- The first line contains two integers $N$ and $M$ — the number of students and the number of suspicious message pairs ($1 \le N \le 100$, $0 \le M \le \frac{N(N-1)}{2}$). |
| 95 | +- The next $M$ lines contain descriptions of student pairs: two integers representing the IDs of the students (numbered from 1). |
| 96 | +- Each pair is listed no more than once. |
| 97 | + |
| 98 | +### Output Format |
| 99 | +Print **YES** if it is possible to divide the students into two groups according to the requirements, and **NO** otherwise. |
| 100 | + |
| 101 | +### Examples |
| 102 | +| Input | Output | |
| 103 | +| :--- | :--- | |
| 104 | +| `3 2` <br> `1 2` <br> `2 3` | `YES` | |
| 105 | +| `3 3` <br> `1 2` <br> `2 3` <br> `1 3` | `NO` | |
| 106 | + |
| 107 | +#include <iostream> |
| 108 | +using namespace std; |
| 109 | + |
| 110 | +int graph[101][101]; |
| 111 | +int color[101]; |
| 112 | +int N; |
| 113 | + |
| 114 | +bool dfs(int v, int col) { |
| 115 | + color[v] = col; |
| 116 | + for (int u = 1; u <= N; u++) { |
| 117 | + if (graph[v][u] == 1) { |
| 118 | + if (color[u] == 0) { |
| 119 | + if (!dfs(u, 3 - col)) { |
| 120 | + return false; |
| 121 | + } |
| 122 | + } else if (color[u] == col) { |
| 123 | + return false; |
| 124 | + } |
| 125 | + } |
| 126 | + } |
| 127 | + return true; |
| 128 | +} |
| 129 | + |
| 130 | +int main() { |
| 131 | + int M; |
| 132 | + cin >> N >> M; |
| 133 | + for (int i = 1; i <= N; i++) { |
| 134 | + color[i] = 0; |
| 135 | + for (int j = 1; j <= N; j++) { |
| 136 | + graph[i][j] = 0; |
| 137 | + } |
| 138 | + } |
| 139 | + for (int i = 0; i < M; i++) { |
| 140 | + int a, b; |
| 141 | + cin >> a >> b; |
| 142 | + graph[a][b] = 1; |
| 143 | + graph[b][a] = 1; |
| 144 | + } |
| 145 | + |
| 146 | + bool possible = true; |
| 147 | + for (int i = 1; i <= N; i++) { |
| 148 | + if (color[i] == 0) { |
| 149 | + if (!dfs(i, 1)) { |
| 150 | + possible = false; |
| 151 | + break; |
| 152 | + } |
| 153 | + } |
| 154 | + } |
| 155 | + |
| 156 | + if (possible) { |
| 157 | + cout << "YES" << endl; |
| 158 | + } else { |
| 159 | + cout << "NO" << endl; |
| 160 | + } |
| 161 | + |
| 162 | + return 0; |
| 163 | +} |
| 164 | + |
| 165 | + |
| 166 | +# 1. Wallets and Keys (Кошельки и ключи) |
| 167 | + |
| 168 | +| | | |
| 169 | +| :--- | :--- | |
| 170 | +| **Input** | Standard input | |
| 171 | +| **Output** | Standard output | |
| 172 | + |
| 173 | +### Problem Statement |
| 174 | +Feofan has $N$ "not-quite-electronic" wallets, numbered from 1 to $N$. Each wallet can be opened only by its unique corresponding key or by being smashed (which is why it's not quite electronic). |
| 175 | + |
| 176 | +Feofan has placed each key inside one of the wallets (you know exactly which key is in which wallet). Now, Feofan needs to access the money in all the wallets while smashing as few of them as possible. Help him determine the minimum number of wallets he needs to smash to get all the keys and open all the wallets. |
| 177 | + |
| 178 | +### Input Format |
| 179 | +- The first line contains the integer $N$ ($1 \le N \le 100,000$) — the number of wallets. |
| 180 | +- The next $N$ lines describe the location of each key: the $i$-th line contains the number of the wallet where the key for the $i$-th wallet is kept. |
| 181 | + |
| 182 | +### Output Format |
| 183 | +Print a single integer — the minimum number of wallets that must be smashed. |
| 184 | + |
| 185 | +### Notes |
| 186 | +In the provided example, smashing wallets 2 and 4 is sufficient to gain access to all of them. |
| 187 | + |
| 188 | +### Examples |
| 189 | +| Input | Output | |
| 190 | +| :--- | :--- | |
| 191 | +| `4` <br> `2` <br> `1` <br> `2` <br> `4` | `2` | |
| 192 | + |
| 193 | +#include <iostream> |
| 194 | +using namespace std; |
| 195 | + |
| 196 | +const int MAXN = 100010; |
| 197 | + |
| 198 | +int a[MAXN]; |
| 199 | +int visited[MAXN]; |
| 200 | + |
| 201 | +int main() { |
| 202 | + int N; |
| 203 | + cin >> N; |
| 204 | + |
| 205 | + for (int i = 1; i <= N; i++) { |
| 206 | + cin >> a[i]; |
| 207 | + visited[i] = 0; |
| 208 | + } |
| 209 | + |
| 210 | + int step = 1; |
| 211 | + int answer = 0; |
| 212 | + |
| 213 | + for (int i = 1; i <= N; i++) { |
| 214 | + if (visited[i] == 0) { |
| 215 | + int v = i; |
| 216 | + while (visited[v] == 0) { |
| 217 | + visited[v] = step; |
| 218 | + v = a[v]; |
| 219 | + } |
| 220 | + |
| 221 | + if (visited[v] == step) { |
| 222 | + answer++; |
| 223 | + } |
| 224 | + |
| 225 | + step++; |
| 226 | + } |
| 227 | + } |
| 228 | + |
| 229 | + cout << answer << endl; |
| 230 | + |
| 231 | + return 0; |
| 232 | +} |
| 233 | + |
| 234 | + |
| 235 | +# 1. Rocket Production (Производство ракеты) |
| 236 | + |
| 237 | +| | | |
| 238 | +| :--- | :--- | |
| 239 | +| **Input** | Standard input | |
| 240 | +| **Output** | Standard output | |
| 241 | +| **Time Limit** | 2 seconds | |
| 242 | +| **Memory Limit** | 64 megabytes | |
| 243 | + |
| 244 | +### Problem Statement |
| 245 | +A rocket intended for a Mars expedition consists of exactly $n$ parts, numbered from 1 to $n$. Each part $i$ takes $t_i$ minutes to manufacture. There is only one factory in the world capable of producing these parts, and it can only work on **one part at a time**. |
| 246 | + |
| 247 | +To produce certain parts, a specific set of other parts must already be manufactured. Your goal is to manufacture **part number 1** in the shortest possible time to present it to investors. Find the minimum time required and the sequence of production. |
| 248 | + |
| 249 | +### Input Format |
| 250 | +- The first line contains an integer $n$ ($1 \le n \le 100,000$) — the number of rocket parts. |
| 251 | +- The second line contains $n$ natural numbers $t_1, t_2, \dots, t_n$ ($t_i \le 10^9$) — the time required to manufacture each part. |
| 252 | +- Each of the following $n$ lines describes the production requirements: |
| 253 | + - The $i$-th line contains the number of parts $c_i$ required to produce part $i$, followed by their IDs. |
| 254 | +- The sum of all $c_i$ does not exceed 200,000. |
| 255 | +- It is guaranteed that there are no cyclic dependencies. |
| 256 | + |
| 257 | +### Output Format |
| 258 | +- **Line 1**: Two numbers — the minimum time (in minutes) required to produce part 1, and the total number of parts $k$ that must be manufactured. |
| 259 | +- **Line 2**: $k$ integers — the IDs of the parts in the order they should be produced. |
| 260 | + |
| 261 | +### Examples |
| 262 | +| Input | Output | |
| 263 | +| :--- | :--- | |
| 264 | +| `3` <br> `100 200 300` <br> `1 2` <br> `0` <br> `2 2 1` | `300 2` <br> `2 1` | |
| 265 | + |
| 266 | +#include <iostream> |
| 267 | +#include <vector> |
| 268 | +using namespace std; |
| 269 | + |
| 270 | +const int MAXV = 100000; |
| 271 | +bool visited[MAXV]; |
| 272 | +int Time[MAXV]; |
| 273 | +vector<int> answer; |
| 274 | +vector<int> g[MAXV]; |
| 275 | +int n; |
| 276 | + |
| 277 | +void dfs(int v) { |
| 278 | + visited[v] = true; |
| 279 | + for (int i : g[v]) { |
| 280 | + if (!visited[i]) |
| 281 | + dfs(i); |
| 282 | + } |
| 283 | + answer.push_back(v); |
| 284 | +} |
| 285 | + |
| 286 | +int main() { |
| 287 | + cin >> n; |
| 288 | + |
| 289 | + for (int i = 0; i < n; ++i) { |
| 290 | + cin >> Time[i]; |
| 291 | + } |
| 292 | + |
| 293 | + for (int i = 0; i < n; ++i) { |
| 294 | + int sz; |
| 295 | + cin >> sz; |
| 296 | + g[i].resize(sz); |
| 297 | + for (int &v : g[i]) { |
| 298 | + cin >> v; |
| 299 | + --v; |
| 300 | + } |
| 301 | + } |
| 302 | + |
| 303 | + for (int i = 0; i < n; ++i) { |
| 304 | + if (!visited[i]) |
| 305 | + dfs(i); |
| 306 | + } |
| 307 | + |
| 308 | + vector<long long> dp(n, 0); |
| 309 | + |
| 310 | + for (int v : answer) { |
| 311 | + long long max_dep_time = 0; |
| 312 | + for (int u : g[v]) { |
| 313 | + if (dp[u] > max_dep_time) { |
| 314 | + max_dep_time = dp[u]; |
| 315 | + } |
| 316 | + } |
| 317 | + dp[v] = max_dep_time + Time[v]; |
| 318 | + } |
| 319 | + |
| 320 | + vector<bool> needed(n, false); |
| 321 | + needed[0] = true; |
| 322 | + |
| 323 | + for (int i = answer.size() - 1; i >= 0; --i) { |
| 324 | + int v = answer[i]; |
| 325 | + if (needed[v]) { |
| 326 | + for (int u : g[v]) { |
| 327 | + needed[u] = true; |
| 328 | + } |
| 329 | + } |
| 330 | + } |
| 331 | + |
| 332 | + vector<int> production_order; |
| 333 | + for (int v : answer) { |
| 334 | + if (needed[v]) { |
| 335 | + production_order.push_back(v); |
| 336 | + } |
| 337 | + } |
| 338 | + long long total_time = 0; |
| 339 | + for (int v : production_order) { |
| 340 | + total_time += Time[v]; |
| 341 | + } |
| 342 | + |
| 343 | + cout << total_time << " " << production_order.size() << "\n"; |
| 344 | + for (int v : production_order) { |
| 345 | + cout << v + 1 << " "; |
| 346 | + } |
| 347 | + cout << "\n"; |
| 348 | + |
| 349 | + return 0; |
| 350 | +} |
| 351 | + |
0 commit comments