解题思路

这是一道需要检测作弊行为的问题,主要思路如下:

  1. 问题分析: 作弊有两种情况:

    • A回答B的问题且B回答A的问题,两人都作弊
    • 如果两个作弊者都回答了C的问题,C也是作弊者
  2. 解决方案:

    • 使用map存储每个人回答了谁的问题
    • 先找出互相回答的作弊者
    • 再找出被作弊者共同回答的人
    • 迭代查找直到没有新的作弊者
  3. 关键点:

    • 使用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

算法及复杂度

  • 算法:图论 + 集合操作
  • 时间复杂度: - 为问题数, 为迭代次数
  • 空间复杂度: - 为回答关系的总数