#P3020. 比赛(100分)
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 224
            Accepted: 68
            Difficulty: 3
            
          
          
          
                       所属公司 : 
                              华为od
                                
            
                      
          
 
- 
                        算法标签>排序算法          
 
比赛(100分)
题解
题目描述:
有 M 个评委对 N 个选手进行评分,评分范围从 1 到 10。每个评委给每个选手打分,且每个评委的评分矩阵已给出。需要根据评分规则,输出得分最多的前三名选手的编号。如果得分相同,则得分高分值最多的选手排名靠前(即先比较 10 分的个数,再比较 9 分的个数,依此类推)。
输入:
- 第一行包含两个整数 
M和N,表示评委的数量和选手的数量。 - 接下来 
M行,每行包含N个整数,表示每个评委对每个选手的评分。 - 分数范围是 
1到10。 
输出:
- 输出前三名选手的编号(从1开始)。
 
约束:
3 <= M <= 103 <= N <= 100- 每个分数在 
1到10之间。 
解题思路:
- 
输入解析:
- 第一行解析 
M和N,分别表示评委数量和选手数量。若不符合约束条件,立即输出-1。 - 接下来读取每个评委的评分,存入二维数组 
scores中。 
 - 第一行解析 
 - 
计算每个选手的得分情况:
- 对每个选手计算总分,并统计每个分数(1分到10分)的频次。
 - 将每个选手的编号与其得分和得分频率存储为一个 
pair<int, vector<int>>对象。int存储选手编号,vector<int>存储总分和频率统计。 
 - 
排序:
- 根据总分进行排序,若总分相同,则按照每个分数的频率进行排序。排序规则:首先比较总分,若相同则依次比较 10 分、9 分、8 分、... 的频率。
 
 - 
输出前三名:
- 排序后输出前三名选手的编号。
 
 
复杂度分析:
- 
时间复杂度:
- 读取输入:
O(M * N) - 计算每个选手的得分:
O(M * N) - 排序:
O(N log N) 
总体复杂度为
O(M * N + N log N)。 - 读取输入:
 - 
空间复杂度:
O(M * N)用于存储评分矩阵。O(N)用于存储选手的得分信息。
 
代码实现:
C++
#include <bits/stdc++.h>
using namespace std;
// 解析输入的逗号分隔的整数
vector<int> parseLine(const string& line) {
vector<int> result;
    stringstream ss(line);
    string token;
    while (getline(ss, token, ',')) {
        result.push_back(stoi(token)); // 将每个分割出来的字符串转成整数
    }
    return result;
}
// 排序函数,首先按总分排序,如果总分相同则按每个分数的频率排序
bool compare(const pair<int, vector<int>>& a, const pair<int, vector<int>>& b) {
    if (a.second[0] != b.second[0]) return a.second[0] > b.second[0]; // 比较总分
    for (int i = 10; i >= 1; --i) { // 如果总分相同,比较各分数的频率
        if (a.second[i] != b.second[i]) return a.second[i] > b.second[i];
    }
    return false;
}
int main() {
    string firstLine;
    getline(cin, firstLine); // 读取第一行输入
    // 解析第一行,获取 M 和 N
    vector<int> firstParams = parseLine(firstLine);
    if (firstParams.size() != 2) {
        cout << -1 << endl; // 输入格式异常
        return 0;
    }
    int M = firstParams[0]; // 评委人数
    int N = firstParams[1]; // 选手人数
    // 检查 M 和 N 是否符合范围
    if (M < 3 || M > 10 || N < 3 || N > 100) {
        cout << -1 << endl; // M 或 N 不合法
        return 0;
    }
    vector<vector<int>> scores(M, vector<int>(N));
    // 读取 M 行评分
    for (int i = 0; i < M; ++i) {
        string line;
        getline(cin, line); // 读取每行评分
        vector<int> row = parseLine(line);
        
        if (row.size() != N) {
            cout << -1 << endl;
            return 0;
        }
        
        for (int j = 0; j < N; ++j) {
            if (row[j] < 1 || row[j] > 10) { // 分数不合法
                cout << -1 << endl;
                return 0;
            }
            scores[i][j] = row[j]; // 存储评分
        }
    }
    // 存储每个选手的总分和分数频率
    vector<pair<int, vector<int>>> players;
    for (int j = 0; j < N; ++j) {
        int totalScore = 0;
        vector<int> scoreFreq(11, 0); // scoreFreq[0] 存储总分,scoreFreq[1]~scoreFreq[10] 存储每个分数的频率
        for (int i = 0; i < M; ++i) {
            int score = scores[i][j];
            totalScore += score; // 累加总分
            scoreFreq[score]++; // 更新分数频率
        }
        scoreFreq[0] = totalScore; // 存储总分
        players.emplace_back(j + 1, scoreFreq); // 存储选手编号及分数信息
    }
    // 排序选手
    sort(players.begin(), players.end(), compare);
    // 输出前3名选手的编号
    cout << players[0].first << "," << players[1].first << "," << players[2].first << endl;
    return 0;
}
Java
import java.util.*;
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String firstLine = scanner.nextLine();
        String[] firstParams = firstLine.split(",");
        
        int M = Integer.parseInt(firstParams[0]);
        int N = Integer.parseInt(firstParams[1]);
        
        if (M < 3 || M > 10 || N < 3 || N > 100) {
            System.out.println(-1);
            return;
        }
        
        int[][] scores = new int[M][N];
        
        // 读取评分矩阵
        for (int i = 0; i < M; i++) {
            String line = scanner.nextLine();
            String[] row = line.split(",");
            if (row.length != N) {
                System.out.println(-1);
                return;
            }
            
            for (int j = 0; j < N; j++) {
                int score = Integer.parseInt(row[j]);
                if (score < 1 || score > 10) {
                    System.out.println(-1);
                    return;
                }
                scores[i][j] =
 score;
            }
        }
        
        List<Player> players = new ArrayList<>();
        
        for (int j = 0; j < N; j++) {
            int totalScore = 0;
            int[] scoreFreq = new int[11];
            for (int i = 0; i < M; i++) {
                int score = scores[i][j];
                totalScore += score;
                scoreFreq[score]++;
            }
            players.add(new Player(j + 1, totalScore, scoreFreq));
        }
        
        // 排序
        players.sort((a, b) -> {
            if (b.totalScore != a.totalScore) {
                return Integer.compare(b.totalScore, a.totalScore);
            }
            for (int i = 10; i >= 1; i--) {
                if (b.scoreFreq[i] != a.scoreFreq[i]) {
                    return Integer.compare(b.scoreFreq[i], a.scoreFreq[i]);
                }
            }
            return 0;
        });
        
        // 输出前三名
        System.out.println(players.get(0).id + "," + players.get(1).id + "," + players.get(2).id);
    }
    static class Player {
        int id;
        int totalScore;
        int[] scoreFreq;
        Player(int id, int totalScore, int[] scoreFreq) {
            this.id = id;
            this.totalScore = totalScore;
            this.scoreFreq = scoreFreq;
        }
    }
}
Python
def parse_line(line):
    # 解析每行输入,返回一个由逗号分隔的整数列表
    return list(map(int, line.split(',')))
def compare(a, b):
    # 比较两个选手的得分和频率
    # 首先比较总分 (a[1][0] 和 b[1][0] 分别是总分)
    if a[1][0] != b[1][0]:
        return b[1][0] - a[1][0]  # 总分较高的选手排前
    
    # 如果总分相同,依次比较每个分数的频率(10分到1分)
    for i in range(10, 0, -1):
        if a[1][i] != b[1][i]:
            return b[1][i] - a[1][i]  # 频率较高的分数排前
    return 0  # 如果总分和所有分数频率完全相同,返回0
def main():
    # 读取第一行输入,包含M和N
    first_line = input()
    M, N = map(int, first_line.split(','))  # 评委人数M和选手人数N
    # 如果M或N不符合题目要求,直接输出-1
    if M < 3 or M > 10 or N < 3 or N > 100:
        print(-1)
        return
    scores = []  # 存储所有评委的评分数据
    # 读取M行评委评分数据
    for _ in range(M):
        line = input()  # 每行表示一个评委的评分
        row = parse_line(line)  # 将逗号分隔的字符串转为整数列表
        
        # 如果该行的选手数量与N不匹配,输出-1
        if len(row) != N:
            print(-1)
            return
        
        # 如果有评分不在合法范围(1-10),也输出-1
        if any(s < 1 or s > 10 for s in row):
            print(-1)
            return
        
        scores.append(row)  # 存储当前评委的评分数据
    players = []  # 存储每个选手的总分和每个分数的频率
    # 计算每个选手的总分以及各个分数的频率
    for j in range(N):
        total_score = sum(scores[i][j] for i in range(M))  # 计算该选手的总分
        score_freq = [0] * 11  # 用一个列表记录每个分数的频率 (score_freq[0] 是总分)
        
        # 计算该选手的每个分数的频率
        for i in range(M):
            score_freq[scores[i][j]] += 1
        
        score_freq[0] = total_score  # 将总分放入score_freq[0]的位置
        players.append((j + 1, score_freq))  # 选手编号从1开始,存储选手编号和其分数频率
    # 按照自定义规则对选手进行排序
    players.sort(key=lambda x: (x[1][0], *x[1][1:]), reverse=True)
    # 排序规则:先按总分排序,如果总分相同,按每个分数的频率(10分到1分)排序
    print(f"{players[0][0]},{players[1][0]},{players[2][0]}")
# 调用主函数
if __name__ == "__main__":
    main()
        题目描述
一共有 N 个选手参加比赛,选手编号为 1 ~ N(3<=N<=100),有 M(3<=M<=10)个评委对选手进行打分。
打分规则为每个评委对选手打分,最高分 10 分,最低分 1 分。
请计算得分最多的 3 位选手的编号。 如果得分相同,则得分高分值最多的选手排名靠前
(10 分数量相同,则比较 9 分的数量,以此类推,用例中不会出现多个选手得分完全相同的情况)。
输入描述
第一行为半角逗号分割的两个正整数,第一个数字表示M(3<=M<=10)个评委,第二个数字表示 N(3<=N<=100)个选手。
第 2 到 M+1 行是半角逗号分割的整数序列,表示评委为每个选手的打分,0 号下标数字表示 1 号选手分数,1 号下标数字表示 2 号选手分数,依次类推。
输出描述
选手前 3 名的编号。
注:若输入为异常,输出 −1 ,如 M、N、打分不在范围内。
样例1
输入
4,5
10,6,9,7,6
9,10,6,7,5
8,10,6,5,10
9,10,8,4,9
输出
2,1,5
说明
第一行代表有 4 个评委, 5 个选手参加比赛
矩阵代表是 4 * 5,每个数字是选手的编号,每一行代表一个评委对选手的打分排序,
2 号选手得分 36 分排第 1 ,
1 号选手 36 分排第 2 ,
5 号选手 30 分
(2 号 10 分值有 3 个,1 号 10 分值只有 1 个,所以 2 号排第一)
样例2
输入
2,5
7,3,5,4,2
8,5,4,4,3
输出
-1
说明
只有 2 个评委,要求最少为 3 个评委
样例3
输入
4,2
8,5
5,6
10,4
8,9
输出
-1
说明
只有 2 名选手参加,要求最少为 3 名
样例4
输入
4,5
11,6,9,7,8
9,10,6,7,8
8,10,6,9,7
9,10,8,6,7
输出
-1
说明
第一个评委给第一个选手打分 11 ,无效分数