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

284 lines
7.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.

"""#
### 谜题描述
You have a simple undirected graph consisting of n vertices and m edges. The graph doesn't contain self-loops, there is at most one edge between a pair of vertices. The given graph can be disconnected.
Let's make a definition.
Let v_1 and v_2 be two some nonempty subsets of vertices that do not intersect. Let f(v_{1}, v_{2}) be true if and only if all the conditions are satisfied:
1. There are no edges with both endpoints in vertex set v_1.
2. There are no edges with both endpoints in vertex set v_2.
3. For every two vertices x and y such that x is in v_1 and y is in v_2, there is an edge between x and y.
Create three vertex sets (v_{1}, v_{2}, v_{3}) which satisfy the conditions below;
1. All vertex sets should not be empty.
2. Each vertex should be assigned to only one vertex set.
3. f(v_{1}, v_{2}), f(v_{2}, v_{3}), f(v_{3}, v_{1}) are all true.
Is it possible to create such three vertex sets? If it's possible, print matching vertex set for each vertex.
Input
The first line contains two integers n and m (3 ≤ n ≤ 10^{5}, 0 ≤ m ≤ min(3 ⋅ 10^{5}, (n(n-1))/(2))) — the number of vertices and edges in the graph.
The i-th of the next m lines contains two integers a_{i} and b_{i} (1 ≤ a_{i} < b_{i} ≤ n) — it means there is an edge between a_{i} and b_{i}. The graph doesn't contain self-loops, there is at most one edge between a pair of vertices. The given graph can be disconnected.
Output
If the answer exists, print n integers. i-th integer means the vertex set number (from 1 to 3) of i-th vertex. Otherwise, print -1.
If there are multiple answers, print any.
Examples
Input
6 11
1 2
1 3
1 4
1 5
1 6
2 4
2 5
2 6
3 4
3 5
3 6
Output
1 2 2 3 3 3
Input
4 6
1 2
1 3
1 4
2 3
2 4
3 4
Output
-1
Note
In the first example, if v_{1} = \{ 1 \}, v_{2} = \{ 2, 3 \}, and v_{3} = \{ 4, 5, 6 \} then vertex sets will satisfy all conditions. But you can assign vertices to vertex sets in a different way; Other answers like \"2 3 3 1 1 1\" will be accepted as well.
<image>
In the second example, it's impossible to make such vertex sets.
Here is a reference code to solve this task. You can use this to help you genereate cases or validate the solution.
```python
import os
import sys
from atexit import register
from io import BytesIO
sys.stdin = BytesIO(os.read(0, os.fstat(0).st_size))
sys.stdout = BytesIO()
register(lambda: os.write(1, sys.stdout.getvalue()))
input = lambda: sys.stdin.readline().rstrip('\r\n')
n,m = map(int,input().split(\" \"))
connected = [[]for i in range(n+1)]
edges = []
for i in range(m):
a,b = map(int,input().split(\" \"))
connected[a].append(b)
connected[b].append(a)
edges.append((a,b))
flag = True
labels = [0]*(n+1)
labels[1] = 1
alln = set(range(1,n+1))
if len(connected[1]) >0:
node2 = connected[1][0]
else:
flag = False
if flag:
s1 = alln-set(connected[1])
s2 = alln-set(connected[node2])
s3 = alln-s1-s2
n1,n2,n3 = len(s1),len(s2),len(s3)
if n1+n2+n3!=n or min(n1,n2,n3) == 0:
flag = False
for i in list(s1):
labels[i] = 1
for i in list(s2):
labels[i] = 2
for i in list(s3):
labels[i] = 3
cnts = [0]*3
for a,b in edges:
if labels[a] == labels[b]:
flag = False
break
cnts[labels[a]-1] += 1
cnts[labels[b]-1] += 1
if flag and cnts[0] == n1*(n2+n3) and cnts[1] == n2*(n1+n3) and cnts[2] == n3*(n1+n2):
out = []
for i in range(1,n+1):
out.append(str(labels[i]))
print \" \".join(out)
else:
print -1
else:
print -1
```
请完成上述谜题的训练场环境类实现,包括所有必要的方法。
"""
from bootcamp import Basebootcamp
from bootcamp import Basebootcamp
import re
import random
class Dcompletetripartitebootcamp(Basebootcamp):
def __init__(self):
super().__init__()
def case_generator(self):
# 生成符合题目要求的n范围 (3 ≤ n ≤ 1e5)
n = random.randint(3, 20) # 示例使用较小范围便于测试实际可调至1e5
# 确保三个子集都至少有一个顶点
sizes = [1, 1, 1]
remaining = n - 3
for _ in range(remaining):
sizes[random.randint(0, 2)] += 1
# 随机分配顶点到三个子集
vertices = list(range(1, n+1))
random.shuffle(vertices)
v1 = sorted(vertices[:sizes[0]])
v2 = sorted(vertices[sizes[0]:sizes[0]+sizes[1]])
v3 = sorted(vertices[sizes[0]+sizes[1]:])
# 计算跨子集边的总数(数学公式直接计算)
m = sizes[0]*sizes[1] + sizes[1]*sizes[2] + sizes[2]*sizes[0]
# 生成边集合(仅记录跨子集的边)
edges = []
# V1-V2边
for a in v1:
edges.extend((min(a,b), max(a,b)) for b in v2)
# V2-V3边
for b in v2:
edges.extend((min(b,c), max(b,c)) for c in v3)
# V3-V1边
for c in v3:
edges.extend((min(c,a), max(c,a)) for a in v1)
# 去重并排序
edges = sorted(list(set(edges)))
return {
"n": n,
"m": len(edges),
"edges": edges,
"expected_sets": {
1: v1,
2: v2,
3: v3
}
}
@staticmethod
def prompt_func(question_case) -> str:
input_lines = [f"{question_case['n']} {question_case['m']}"]
input_lines.extend(f"{a} {b}" for a, b in question_case['edges'])
input_block = "\n".join(input_lines)
prompt = f"""Given an undirected graph with {question_case['n']} vertices and {question_case['m']} edges, determine if the vertices can be partitioned into three non-empty subsets meeting these conditions:
1. All vertices are in exactly one subset
2. For each subset pair (V1,V2), (V2,V3), (V3,V1):
- No internal edges within either subset
- Complete bipartite connections between subsets
Input:
{input_block}
Output format:
If possible: {question_case['n']} space-separated integers (1/2/3)
If impossible: -1
Place your final answer between [answer] and [/answer]. Example:
[answer]1 2 2 3 3 3[/answer]"""
return prompt
@staticmethod
def extract_output(output):
matches = re.findall(r'\[answer\](.*?)\[\/answer\]', output, re.DOTALL)
return matches[-1].strip() if matches else None
@classmethod
def _verify_correction(cls, solution, identity):
# 快速拒绝错误格式
if not solution or solution.strip() == "-1":
return False
try:
labels = list(map(int, solution.split()))
except ValueError:
return False
# 验证基础条件
if len(labels) != identity['n']:
return False
if not all(l in {1,2,3} for l in labels):
return False
# 构建分组映射
groups = {1: set(), 2: set(), 3: set()}
for v, l in enumerate(labels, 1):
groups[l].add(v)
# 检查非空子集
if any(len(groups[i]) == 0 for i in [1,2,3]):
return False
# 验证边约束
edge_set = set(map(tuple, identity['edges']))
# 验证每个子集的内部无连接
for group in groups.values():
for a in group:
for b in group:
if a < b and (a, b) in edge_set:
return False
# 验证跨子集的完全连接
expected_pairs = [
(groups[1], groups[2]),
(groups[2], groups[3]),
(groups[3], groups[1])
]
for s1, s2 in expected_pairs:
for a in s1:
for b in s2:
if a > b:
a, b = b, a
if (a, b) not in edge_set:
return False
return True