mirror of
https://github.com/InternLM/InternBootcamp.git
synced 2026-04-19 12:58:04 +00:00
372 lines
10 KiB
Python
Executable file
372 lines
10 KiB
Python
Executable file
"""#
|
|
|
|
### 谜题描述
|
|
I have an undirected graph consisting of n nodes, numbered 1 through n. Each node has at most two incident edges. For each pair of nodes, there is at most an edge connecting them. No edge connects a node to itself.
|
|
|
|
I would like to create a new graph in such a way that:
|
|
|
|
* The new graph consists of the same number of nodes and edges as the old graph.
|
|
* The properties in the first paragraph still hold.
|
|
* For each two nodes u and v, if there is an edge connecting them in the old graph, there is no edge connecting them in the new graph.
|
|
|
|
|
|
|
|
Help me construct the new graph, or tell me if it is impossible.
|
|
|
|
Input
|
|
|
|
The first line consists of two space-separated integers: n and m (1 ≤ m ≤ n ≤ 105), denoting the number of nodes and edges, respectively. Then m lines follow. Each of the m lines consists of two space-separated integers u and v (1 ≤ u, v ≤ n; u ≠ v), denoting an edge between nodes u and v.
|
|
|
|
Output
|
|
|
|
If it is not possible to construct a new graph with the mentioned properties, output a single line consisting of -1. Otherwise, output exactly m lines. Each line should contain a description of edge in the same way as used in the input format.
|
|
|
|
Examples
|
|
|
|
Input
|
|
|
|
8 7
|
|
1 2
|
|
2 3
|
|
4 5
|
|
5 6
|
|
6 8
|
|
8 7
|
|
7 4
|
|
|
|
|
|
Output
|
|
|
|
1 4
|
|
4 6
|
|
1 6
|
|
2 7
|
|
7 5
|
|
8 5
|
|
2 8
|
|
|
|
|
|
Input
|
|
|
|
3 2
|
|
1 2
|
|
2 3
|
|
|
|
|
|
Output
|
|
|
|
-1
|
|
|
|
|
|
Input
|
|
|
|
5 4
|
|
1 2
|
|
2 3
|
|
3 4
|
|
4 1
|
|
|
|
|
|
Output
|
|
|
|
1 3
|
|
3 5
|
|
5 2
|
|
2 4
|
|
|
|
Note
|
|
|
|
The old graph of the first example:
|
|
|
|
<image>
|
|
|
|
A possible new graph for the first example:
|
|
|
|
<image>
|
|
|
|
In the second example, we cannot create any new graph.
|
|
|
|
The old graph of the third example:
|
|
|
|
<image>
|
|
|
|
A possible new graph for the third example:
|
|
|
|
<image>
|
|
|
|
Here is a reference code to solve this task. You can use this to help you genereate cases or validate the solution.
|
|
```python
|
|
import random
|
|
s = raw_input().split()
|
|
|
|
n = int(s[0])
|
|
m = int(s[1])
|
|
|
|
graf = set([])
|
|
|
|
for i in xrange(m):
|
|
s = raw_input().split()
|
|
u = int(s[0])
|
|
v = int(s[1])
|
|
graf.add((u,v))
|
|
|
|
#print graf
|
|
if m*4>n*(n-1):
|
|
print -1
|
|
else:
|
|
edges = 0
|
|
tries = 0
|
|
listv = range(1,n+1)
|
|
while edges < m:
|
|
tries += 1
|
|
if (tries > 10000):
|
|
break
|
|
edges = 0
|
|
|
|
random.shuffle(listv)
|
|
for i in xrange(m):
|
|
u = listv[i-1]
|
|
v = listv[i]
|
|
edges = i+1
|
|
if ((u,v) in graf) or ((v,u) in graf):
|
|
edges = 0
|
|
break
|
|
|
|
if (tries > 10000):
|
|
print -1
|
|
else:
|
|
for i in xrange(m):
|
|
print listv[i-1], listv[i]
|
|
```
|
|
|
|
|
|
请完成上述谜题的训练场环境类实现,包括所有必要的方法。
|
|
"""
|
|
|
|
from bootcamp import Basebootcamp
|
|
import random
|
|
from collections import defaultdict
|
|
from bootcamp import Basebootcamp
|
|
|
|
class Egraphreconstructionbootcamp(Basebootcamp):
|
|
def __init__(self, max_nodes=10, prob_impossible=0.3):
|
|
super().__init__()
|
|
self.max_nodes = max_nodes
|
|
self.prob_impossible = prob_impossible # 控制不可解案例生成概率
|
|
|
|
def case_generator(self):
|
|
"""智能案例生成:平衡可解/不可解案例"""
|
|
# 特殊已知不可解案例
|
|
if random.random() < 0.2:
|
|
return {'n': 3, 'm': 2, 'edges': [(1,2), (2,3)], 'impossible': True}
|
|
|
|
# 按概率尝试生成不可解案例
|
|
if random.random() < self.prob_impossible:
|
|
case = self._generate_impossible_case()
|
|
if case:
|
|
return case
|
|
|
|
# 生成可解案例(确保存在解)
|
|
for _ in range(100):
|
|
n = random.randint(3, self.max_nodes)
|
|
max_m = min(n, n*(n-1)//2)
|
|
if max_m == 0:
|
|
continue
|
|
m = random.randint(1, max_m)
|
|
case = self._generate_solvable_case(n, m)
|
|
if case:
|
|
return case
|
|
|
|
# 回退到简单案例
|
|
return {'n': 4, 'm': 2, 'edges': [(1,2), (3,4)], 'impossible': False}
|
|
|
|
def _generate_impossible_case(self):
|
|
"""生成真正不可解的案例(数学约束+构造验证)"""
|
|
for _ in range(100):
|
|
# 1. 满足数学边界条件
|
|
n = random.randint(5, self.max_nodes) # n至少5以保证可能无法构造
|
|
min_m = (n*(n-1)//4) + 1
|
|
max_m = min(2*n, n*(n-1)//2) # 边数上限调整为实际可能值
|
|
if min_m > max_m:
|
|
continue
|
|
m = random.randint(min_m, max_m)
|
|
|
|
# 2. 生成合法原始图
|
|
edges = []
|
|
degrees = defaultdict(int)
|
|
candidates = [(i,j) for i in range(1,n+1) for j in range(i+1,n+1)]
|
|
random.shuffle(candidates)
|
|
|
|
for u, v in candidates:
|
|
if len(edges) >= m:
|
|
break
|
|
if degrees[u] < 2 and degrees[v] < 2:
|
|
edges.append((u, v))
|
|
degrees[u] += 1
|
|
degrees[v] += 1
|
|
|
|
# 3. 验证实际无法构造解
|
|
if len(edges) == m and self._is_truly_impossible(n, m, edges):
|
|
return {'n': n, 'm': m, 'edges': edges, 'impossible': True}
|
|
return None
|
|
|
|
def _is_truly_impossible(self, n, m, original_edges):
|
|
"""双重验证:数学条件+构造验证"""
|
|
# 数学条件验证
|
|
if 4*m > n*(n-1):
|
|
return True
|
|
|
|
# 实际构造尝试(优化版)
|
|
original_set = {tuple(sorted(e)) for e in original_edges}
|
|
for _ in range(1000):
|
|
# 使用参考算法的方法
|
|
nodes = list(range(1, n+1))
|
|
random.shuffle(nodes)
|
|
valid = True
|
|
for i in range(m):
|
|
u = nodes[i-1]
|
|
v = nodes[i]
|
|
if tuple(sorted((u, v))) in original_set:
|
|
valid = False
|
|
break
|
|
if valid:
|
|
return False # 存在解
|
|
return True # 未找到解
|
|
|
|
def _generate_solvable_case(self, n, m):
|
|
"""生成保证可解的案例"""
|
|
# 生成解方案
|
|
nodes = list(range(1, n+1))
|
|
random.shuffle(nodes)
|
|
solution_edges = {tuple(sorted((nodes[i-1], nodes[i]))) for i in range(m)}
|
|
|
|
# 生成原始边(排除解方案)
|
|
edges = []
|
|
degrees = defaultdict(int)
|
|
candidates = [(i,j) for i in range(1,n+1) for j in range(i+1,n+1)
|
|
if tuple(sorted((i,j))) not in solution_edges]
|
|
random.shuffle(candidates)
|
|
|
|
for u, v in candidates:
|
|
if len(edges) >= m:
|
|
break
|
|
if degrees[u] < 2 and degrees[v] < 2:
|
|
edges.append((u, v))
|
|
degrees[u] += 1
|
|
degrees[v] += 1
|
|
|
|
if len(edges) == m:
|
|
return {'n': n, 'm': m, 'edges': edges, 'impossible': False}
|
|
return None
|
|
|
|
@staticmethod
|
|
def prompt_func(question_case):
|
|
edges = '\n'.join(f"{u} {v}" for u, v in question_case['edges'])
|
|
return f"""You are a graph theory expert. Solve the following problem:
|
|
|
|
Original Graph:
|
|
- Nodes: {question_case['n']}
|
|
- Edges ({question_case['m']}):
|
|
{edges}
|
|
|
|
Task:
|
|
1. Create a new graph with same node/edge counts
|
|
2. Each node must have ≤2 edges
|
|
3. No overlapping edges with original
|
|
4. Output format:
|
|
- If impossible: only '-1'
|
|
- Else: {question_case['m']} edges in ascending order
|
|
|
|
Put your final answer within [ANSWER] tags like:
|
|
[ANSWER]
|
|
1 2
|
|
3 4
|
|
...[/ANSWER]"""
|
|
|
|
@staticmethod
|
|
def extract_output(output):
|
|
import re
|
|
# 优先匹配标签内容
|
|
tag_match = re.search(r'\[ANSWER\](.*?)\[/ANSWER\]', output, re.DOTALL | re.IGNORECASE)
|
|
if tag_match:
|
|
content = tag_match.group(1).strip()
|
|
if re.match(r'^\s*-1\s*$', content):
|
|
return -1
|
|
edges = []
|
|
for line in content.splitlines():
|
|
line = line.strip()
|
|
if re.fullmatch(r'\d+\s+\d+', line):
|
|
u, v = map(int, line.split())
|
|
edges.append((min(u,v), max(u,v)))
|
|
return edges if edges else None
|
|
|
|
# 次优匹配:最后的-1或边序列
|
|
lines = [line.strip() for line in output.splitlines()]
|
|
for line in reversed(lines):
|
|
if line == '-1':
|
|
return -1
|
|
edges = []
|
|
for line in reversed(lines):
|
|
if re.fullmatch(r'\d+\s+\d+', line):
|
|
u, v = map(int, line.split())
|
|
edges.append((min(u,v), max(u,v)))
|
|
elif edges:
|
|
break
|
|
return list(reversed(edges)) if edges else None
|
|
|
|
@classmethod
|
|
def _verify_correction(cls, solution, identity):
|
|
original_edges = {tuple(sorted(e)) for e in identity['edges']}
|
|
n, m = identity['n'], identity['m']
|
|
|
|
if solution == -1:
|
|
# 双重验证机制
|
|
return cls._is_truly_impossible_wrapper(n, m, original_edges)
|
|
|
|
# 验证正解
|
|
if len(solution) != m:
|
|
return False
|
|
|
|
seen = set()
|
|
degrees = defaultdict(int)
|
|
for u, v in solution:
|
|
# 数值有效性
|
|
if not (1 <= u <= n) or not (1 <= v <= n) or u == v:
|
|
return False
|
|
edge = (min(u,v), max(u,v))
|
|
|
|
# 冲突检查
|
|
if edge in seen or edge in original_edges:
|
|
return False
|
|
seen.add(edge)
|
|
|
|
# 度数检查
|
|
degrees[u] += 1
|
|
degrees[v] += 1
|
|
if degrees[u] > 2 or degrees[v] > 2:
|
|
return False
|
|
|
|
return True
|
|
|
|
@classmethod
|
|
def _is_truly_impossible_wrapper(cls, n, m, original_edges):
|
|
"""统一的不可解验证逻辑"""
|
|
# 快速数学检查
|
|
if 4*m > n*(n-1):
|
|
return True
|
|
|
|
# 构造试错(优化性能)
|
|
original_set = original_edges
|
|
for _ in range(1000):
|
|
nodes = list(range(1, n+1))
|
|
random.shuffle(nodes)
|
|
conflict = False
|
|
for i in range(m):
|
|
u = nodes[i-1]
|
|
v = nodes[i]
|
|
if tuple(sorted((u, v))) in original_set:
|
|
conflict = True
|
|
break
|
|
if not conflict:
|
|
return False # 存在解
|
|
return True
|