InternBootcamp/internbootcamp/bootcamp/csergeysproblem/csergeysproblem.py
2025-05-23 15:27:15 +08:00

236 lines
6.9 KiB
Python
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""#
### 谜题描述
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