解题思路
这是一道需要检测作弊行为的问题,主要思路如下:
-
问题分析: 作弊有两种情况:
- A回答B的问题且B回答A的问题,两人都作弊
- 如果两个作弊者都回答了C的问题,C也是作弊者
-
解决方案:
- 使用map存储每个人回答了谁的问题
- 先找出互相回答的作弊者
- 再找出被作弊者共同回答的人
- 迭代查找直到没有新的作弊者
-
关键点:
- 使用set去重
- 需要多轮检查直到没有新增作弊者
- 注意输出格式
代码
#include <iostream>
#include <map>
#include <set>
using namespace std;
int main() {
int n;
while (cin >> n) {
// 存储每个人回答了谁的问题
map<int, set<int>> answers;
// 读取所有问题
for (int i = 0; i < n; i++) {
int askId, num;
cin >> askId >> num;
// 读取所有回答者
for (int j = 0; j < num; j++) {
int answerId;
cin >> answerId;
if (answerId != askId) { // 排除自问自答
answers[askId].insert(answerId);
}
}
}
// 存储作弊者
set<int> cheaters;
// 找出互相回答的作弊者
for (auto& pair : answers) {
for (int answerId : pair.second) {
if (answers.count(answerId) &&
answers[answerId].count(pair.first)) {
cheaters.insert(pair.first);
cheaters.insert(answerId);
}
}
}
// 找出被作弊者共同回答的人
int prevSize;
do {
prevSize = cheaters.size();
for (auto& pair : answers) {
int count = 0;
for (int answerId : pair.second) {
if (cheaters.count(answerId)) count++;
}
if (count >= 2) cheaters.insert(pair.first);
}
} while (prevSize != cheaters.size());
// 输出结果
cout << cheaters.size() << endl;
bool first = true;
for (int id : cheaters) {
if (!first) cout << " ";
cout << id;
first = false;
}
if (cheaters.size() > 0) cout << endl;
}
return 0;
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()) {
int n = sc.nextInt();
// 存储每个人回答了谁的问题
Map<Integer, Set<Integer>> answers = new HashMap<>();
// 读取所有问题
for (int i = 0; i < n; i++) {
int askId = sc.nextInt();
int num = sc.nextInt();
// 读取所有回答者
for (int j = 0; j < num; j++) {
int answerId = sc.nextInt();
if (answerId != askId) { // 排除自问自答
answers.computeIfAbsent(askId, k -> new HashSet<>())
.add(answerId);
}
}
}
// 存储作弊者
TreeSet<Integer> cheaters = new TreeSet<>();
// 找出互相回答的作弊者
for (Map.Entry<Integer, Set<Integer>> entry : answers.entrySet()) {
for (int answerId : entry.getValue()) {
if (answers.containsKey(answerId) &&
answers.get(answerId).contains(entry.getKey())) {
cheaters.add(entry.getKey());
cheaters.add(answerId);
}
}
}
// 找出被作弊者共同回答的人
int prevSize;
do {
prevSize = cheaters.size();
for (Map.Entry<Integer, Set<Integer>> entry : answers.entrySet()) {
int count = 0;
for (int answerId : entry.getValue()) {
if (cheaters.contains(answerId)) count++;
}
if (count >= 2) cheaters.add(entry.getKey());
}
} while (prevSize != cheaters.size());
// 输出结果
System.out.println(cheaters.size());
boolean first = true;
for (int id : cheaters) {
if (!first) System.out.print(" ");
System.out.print(id);
first = false;
}
if (cheaters.size() > 0) System.out.println();
}
}
}
from collections import defaultdict
def find_cheaters(n, questions):
# 存储每个人回答了谁的问题
answers = defaultdict(set)
# 处理所有问题
for ask_id, answer_ids in questions:
for answer_id in answer_ids:
if answer_id != ask_id: # 排除自问自答
answers[ask_id].add(answer_id)
# 存储作弊者
cheaters = set()
# 找出互相回答的作弊者
for ask_id, answerers in answers.items():
for answer_id in answerers:
if ask_id in answers.get(answer_id, set()):
cheaters.add(ask_id)
cheaters.add(answer_id)
# 找出被作弊者共同回答的人
while True:
prev_size = len(cheaters)
for ask_id, answerers in answers.items():
if sum(1 for x in answerers if x in cheaters) >= 2:
cheaters.add(ask_id)
if len(cheaters) == prev_size:
break
return sorted(cheaters)
# 处理输入
while True:
try:
n = int(input())
questions = []
for _ in range(n):
line = list(map(int, input().split()))
ask_id, num = line[0], line[1]
answer_ids = line[2:]
questions.append((ask_id, answer_ids))
# 获取并输出结果
result = find_cheaters(n, questions)
print(len(result))
if len(result) > 0:
print(" ".join(map(str, result)))
except EOFError:
break
算法及复杂度
- 算法:图论 + 集合操作
- 时间复杂度:
-
为问题数,
为迭代次数
- 空间复杂度:
-
为回答关系的总数