mirror of
https://github.com/InternLM/InternBootcamp.git
synced 2026-04-22 16:49:04 +00:00
236 lines
6.9 KiB
Python
Executable file
236 lines
6.9 KiB
Python
Executable file
"""#
|
||
|
||
### 谜题描述
|
||
Sergey just turned five years old! When he was one year old, his parents gave him a number; when he was two years old, his parents gave him an array of integers. On his third birthday he received a string. When he was four, his mother woke him up in a quiet voice, wished him to be a good boy and gave him a rooted tree. Today he celebrates his birthday again! He found a directed graph without loops as a present from his parents.
|
||
|
||
Since Sergey is a very curious boy, he immediately came up with a thing to do. He decided to find a set Q of vertices in this graph, such that no two vertices x, y ∈ Q are connected by an edge, and it is possible to reach any vertex z ∉ Q from some vertex of Q in no more than two moves.
|
||
|
||
After a little thought, Sergey was able to solve this task. Can you solve it too?
|
||
|
||
A vertex y is reachable from a vertex x in at most two moves if either there is a directed edge (x,y), or there exist two directed edges (x,z) and (z, y) for some vertex z.
|
||
|
||
Input
|
||
|
||
The first line of input contains two positive integers n and m (1 ≤ n ≤ 1 000 000, 1 ≤ m ≤ 1 000 000) — the number of vertices and the number of edges in the directed graph.
|
||
|
||
Each of the following m lines describes a corresponding edge. Each one contains two integers a_i and b_i (1 ≤ a_i, b_i ≤ n, a_i ≠ b_i) — the beginning and the end of the i-th edge. The graph may contain multiple edges between the same pair of vertices.
|
||
|
||
Output
|
||
|
||
First print the number k — the number of selected vertices. Then print k distinct integers — the indices of the selected vertices.
|
||
|
||
If multiple answers exist you can output any of them. In particular, you don't have to minimize the number of vertices in the set. It is guaranteed, that there is always at least one valid set.
|
||
|
||
Examples
|
||
|
||
Input
|
||
|
||
5 4
|
||
1 2
|
||
2 3
|
||
2 4
|
||
2 5
|
||
|
||
|
||
Output
|
||
|
||
4
|
||
1 3 4 5
|
||
|
||
|
||
Input
|
||
|
||
3 3
|
||
1 2
|
||
2 3
|
||
3 1
|
||
|
||
|
||
Output
|
||
|
||
1
|
||
3
|
||
|
||
Note
|
||
|
||
In the first sample, the vertices 1, 3, 4, 5 are not connected. The vertex 2 is reachable from vertex 1 by one edge.
|
||
|
||
In the second sample, it is possible to reach the vertex 1 in one move and the vertex 2 in two moves.
|
||
|
||
The following pictures illustrate sample tests and their answers.
|
||
|
||
<image> <image>
|
||
|
||
Here is a reference code to solve this task. You can use this to help you genereate cases or validate the solution.
|
||
```python
|
||
#include <bits/stdc++.h>
|
||
using namespace std;
|
||
const int N = 1000010;
|
||
const int mod = 1000000007;
|
||
int n, m;
|
||
vector<int> g[N];
|
||
int v[N];
|
||
int main() {
|
||
cin >> n >> m;
|
||
memset(v, 0, sizeof(v));
|
||
for (int i = 0; i < m; ++i) {
|
||
int u, v;
|
||
scanf(\"%d%d\", &u, &v);
|
||
g[u].push_back(v);
|
||
}
|
||
for (int i = 1; i < n + 1; ++i) {
|
||
if (v[i]) continue;
|
||
for (int u : g[i]) {
|
||
if (u > i) v[u] = 1;
|
||
}
|
||
}
|
||
int num = 0;
|
||
for (int i = n; i > 0; --i) {
|
||
if (v[i]) continue;
|
||
for (int u : g[i]) {
|
||
if (u < i) v[u] = 1;
|
||
}
|
||
++num;
|
||
}
|
||
printf(\"%d\n\", num);
|
||
for (int i = 1; i < n + 1; ++i)
|
||
if (!v[i]) printf(\"%d \", i);
|
||
printf(\"\n\");
|
||
}
|
||
```
|
||
|
||
|
||
请完成上述谜题的训练场环境类实现,包括所有必要的方法。
|
||
"""
|
||
|
||
from bootcamp import Basebootcamp
|
||
import re
|
||
import random
|
||
from collections import defaultdict
|
||
from bootcamp import Basebootcamp
|
||
|
||
class Csergeysproblembootcamp(Basebootcamp):
|
||
def __init__(self, **params):
|
||
self.n = params.get('n', 5)
|
||
self.m = params.get('m', 4)
|
||
|
||
def case_generator(self):
|
||
n = self.n
|
||
m = self.m
|
||
edges = []
|
||
for _ in range(m):
|
||
a = random.randint(1, n)
|
||
b = random.randint(1, n)
|
||
while a == b:
|
||
b = random.randint(1, n)
|
||
edges.append((a, b))
|
||
return {
|
||
'n': n,
|
||
'm': m,
|
||
'edges': edges
|
||
}
|
||
|
||
@staticmethod
|
||
def prompt_func(question_case):
|
||
n = question_case['n']
|
||
m = question_case['m']
|
||
edges = question_case['edges']
|
||
input_lines = [f"{n} {m}"] + [f"{a} {b}" for a, b in edges]
|
||
input_example = '\n'.join(input_lines)
|
||
prompt = f"""Sergey在他的五岁生日时得到了一个有向图,他需要找到满足特定条件的顶点集合Q。具体规则如下:
|
||
|
||
1. Q中的任意两个顶点之间不能有直接相连的边(即不存在边x→y或y→x,其中x和y都属于Q)。
|
||
2. 所有不在Q中的顶点z必须满足:至少存在一个顶点x属于Q,使得z可以通过x的一步或两步到达(即存在x→z的边,或存在中间顶点u,使得x→u→z的路径)。
|
||
|
||
你的任务是,给定一个有向图,找到这样的集合Q。输出可以是任意有效解,无需最小化集合大小。
|
||
|
||
输入格式:
|
||
第一行包含两个整数n和m(顶点数和边数)。
|
||
接下来的m行每行两个整数a_i和b_i,表示一条有向边。
|
||
|
||
输出格式:
|
||
第一行输出k(集合Q的顶点数量),第二行输出k个不同的顶点编号,按任意顺序排列,用空格分隔。
|
||
|
||
例如,输入:
|
||
5 4
|
||
1 2
|
||
2 3
|
||
2 4
|
||
2 5
|
||
有效输出:
|
||
4
|
||
1 3 4 5
|
||
|
||
现在,给定以下输入,请找出符合条件的顶点集合Q,并将答案按格式包含在[answer]和[/answer]标签中:
|
||
|
||
输入:
|
||
{input_example}
|
||
|
||
请将最终答案放在[answer]标签内。例如:
|
||
[answer]
|
||
3
|
||
1 2 3
|
||
[/answer]"""
|
||
return prompt
|
||
|
||
@staticmethod
|
||
def extract_output(output):
|
||
pattern = r'\[answer\](.*?)\[/answer\]'
|
||
matches = re.findall(pattern, output, re.DOTALL)
|
||
if not matches:
|
||
return None
|
||
content = matches[-1].strip()
|
||
numbers = re.findall(r'\d+', content)
|
||
if len(numbers) < 1:
|
||
return None
|
||
try:
|
||
k = int(numbers[0])
|
||
if len(numbers) != k + 1:
|
||
return None
|
||
solution = list(map(int, numbers[1:]))
|
||
if len(solution) != len(set(solution)):
|
||
return None
|
||
return solution
|
||
except (ValueError, IndexError):
|
||
return None
|
||
|
||
@classmethod
|
||
def _verify_correction(cls, solution, identity):
|
||
try:
|
||
if not isinstance(solution, list):
|
||
return False
|
||
q = list(map(int, solution))
|
||
if len(q) != len(set(q)):
|
||
return False
|
||
except:
|
||
return False
|
||
|
||
n = identity['n']
|
||
edges = identity['edges']
|
||
q_set = set(q)
|
||
if any(x < 1 or x > n for x in q):
|
||
return False
|
||
|
||
for a, b in edges:
|
||
if a in q_set and b in q_set:
|
||
return False
|
||
|
||
adj = defaultdict(list)
|
||
for a, b in edges:
|
||
adj[a].append(b)
|
||
|
||
coverage = set()
|
||
for x in q_set:
|
||
step1 = adj.get(x, [])
|
||
step2 = []
|
||
for u in step1:
|
||
step2.extend(adj.get(u, []))
|
||
coverage.update(step1)
|
||
coverage.update(step2)
|
||
|
||
all_vertices = set(range(1, n+1))
|
||
z_vertices = all_vertices - q_set
|
||
for z in z_vertices:
|
||
if z not in coverage:
|
||
return False
|
||
return True
|