PAT:1012 The Best Rank (25分)(自定义排序+排序变量)

该博客讨论了PAT比赛中的一道题目,涉及如何为学生计算他们在C语言、数学和英语三门课程及平均分中的最佳排名。博主分享了对排序算法和数据存储的思考,特别是面对相同排名时如何按学科优先级输出的问题。尽管感到挫败,博主鼓励自己继续努力解决这个问题。

To evaluate the performance of our first year CS majored students, we consider their grades of three courses only: C - C Programming Language, M - Mathematics (Calculus or Linear Algrbra), and E - English. At the mean time, we encourage students by emphasizing on their best ranks -- that is, among the four ranks with respect to the three courses and the average grade, we print the best rank for each student.

For example, The grades of CME and A - Average of 4 students are given as the following:

StudentID  C  M  E  A
310101     98 85 88 90
310102     70 95 88 84
310103     82 87 94 88
310104     91 91 91 91

Then the best ranks for all the students are No.1 since the 1st one has done the best in C Programming Language, while the 2nd one in Mathematics, the 3rd one in English, and the last one in average.

Input Specification:

Each input file contains one test case. Each case starts with a line containing 2 numbers N and M (≤2000), which are the total number of students, and the number of students who would check their ranks, respectively. Then N lines follow, each contains a student ID which is a string of 6 digits, followed by the three integer grades (in the range of [0, 100]) of that student in the order of CM and E. Then there are M lines, each containing a student ID.

Output Specification:

For each of the M students, print in one line the best rank for him/her, and the symbol of the corresponding rank, separated by a space.

The priorities of the ranking methods are ordered as A > C > M > E. Hence if there are two or more ways for a student to obtain the same best rank, output the one with the highest priority.

If a student is not on the grading list, simply output N/A.

Sample Input:

5 6
310101 98 85 88
310102 70 95 88
310103 82 87 94
310104 91 91 91
310105 85 90 90
310101
310102
310103
310104
310105
999999

Sample Output:

1 C
1 M
1 E
1 A
3 A
N/A

作者

这道题做了两次了,这次还是不会,诶,太挫败了,但还得加油啊,问题在于怎么排序呢,排序后又该怎么存储,因为对于相同的名次,还要按照规定的学科次序来输出,而学科次序已经是确定了,所以是比较简单的,就算没有确定呢,我们也可以通过改变输入顺序来确定,

难点在于排序,每个都要派,又该怎么存储?,这里就得用二维数组了,可惜我的脑子实在想不出来,真的太菜了,用二位数字来存储四个成绩不就行了呗

#include<bits/stdc++.h>
using namespace std;
struct node
{
    int id;
    int grade[4];
};
int now;
int course[1001000][4]={0};
char test[4]={'A','C','M','E'};
bool cmp(node a,node b)
{
    return a.grade[now]>b.grade[now];
}
int main()
{
    int n,m;
    cin>>n>>m;
    node a[n];
    for(int i=0;i<n;i++){
        cin>>a[i].id>>a[i].grade[1]>>a[i].grade[2]>>a[i].grade[3];
        a[i].grade[0]=(a[i].grade[1]+a[i].grade[2]+a[i].grade[3])/3+0.5;
    }
    for(now=0;now<4;now++){
        sort(a,a+n,cmp);
        course[a[0].id][now]=1;
        for(int i=0;i<n;i++){
            if(a[i].grade[now]==a[i-1].grade[now]){
                course[a[i].id][now]=course[a[i-1].id][now];
            }
            else
                course[a[i].id][now]=i+1;
        }

    }
    int query;
    for(int i=0;i<m;i++){
        cin>>query;
        if(course[query][0]==0){
            printf("N/A\n");
        }
        else{
            int k=0;
            for(int j=1;j<4;j++){
                if(course[query][j]<course[query][k]){
                    k=j;
                }
            }
            cout<<course[query][k]<<" "<<test[k]<<endl;
        }
    }

}

 

#!/usr/bin/env pypy3 from __future__ import print_function import time, math from itertools import count from collections import namedtuple, defaultdict # If we could rely on the env -S argument, we could just use "pypy3 -u" # as the shebang to unbuffer stdout. But alas we have to do this instead: #from functools import partial #print = partial(print, flush=True) version = "sunfish 2023" ############################################################################### # Piece-Square tables. Tune these to change sunfish's behaviour ############################################################################### # With xz compression this whole section takes 652 bytes. # That's pretty good given we have 64*6 = 384 values. # Though probably we could do better... # For one thing, they could easily all fit into int8. piece = {"P": 100, "N": 280, "B": 320, "R": 479, "Q": 929, "K": 60000} pst = { 'P': ( 0, 0, 0, 0, 0, 0, 0, 0, 78, 83, 86, 73, 102, 82, 85, 90, 7, 29, 21, 44, 40, 31, 44, 7, -17, 16, -2, 15, 14, 0, 15, -13, -26, 3, 10, 9, 6, 1, 0, -23, -22, 9, 5, -11, -10, -2, 3, -19, -31, 8, -7, -37, -36, -14, 3, -31, 0, 0, 0, 0, 0, 0, 0, 0), 'N': ( -66, -53, -75, -75, -10, -55, -58, -70, -3, -6, 100, -36, 4, 62, -4, -14, 10, 67, 1, 74, 73, 27, 62, -2, 24, 24, 45, 37, 33, 41, 25, 17, -1, 5, 31, 21, 22, 35, 2, 0, -18, 10, 13, 22, 18, 15, 11, -14, -23, -15, 2, 0, 2, 0, -23, -20, -74, -23, -26, -24, -19, -35, -22, -69), 'B': ( -59, -78, -82, -76, -23,-107, -37, -50, -11, 20, 35, -42, -39, 31, 2, -22, -9, 39, -32, 41, 52, -10, 28, -14, 25, 17, 20, 34, 26, 25, 15, 10, 13, 10, 17, 23, 17, 16, 0, 7, 14, 25, 24, 15, 8, 25, 20, 15, 19, 20, 11, 6, 7, 6, 20, 16, -7, 2, -15, -12, -14, -15, -10, -10), 'R': ( 35, 29, 33, 4, 37, 33, 56, 50, 55, 29, 56, 67, 55, 62, 34, 60, 19, 35, 28, 33, 45, 27, 25, 15, 0, 5, 16, 13, 18, -4, -9, -6, -28, -35, -16, -21, -13, -29, -46, -30, -42, -28, -42, -25, -25, -35, -26, -46, -53, -38, -31, -26, -29, -43, -44, -53, -30, -24, -18, 5, -2, -18, -31, -32), 'Q': ( 6, 1, -8,-104, 69, 24, 88, 26, 14, 32, 60, -10, 20, 76, 57, 24, -2, 43, 32, 60, 72, 63, 43, 2, 1, -16, 22, 17, 25, 20, -13, -6, -14, -15, -2, -5, -1, -10, -20, -22, -30, -6, -13, -11, -16, -11, -16, -27, -36, -18, 0, -19, -15, -15, -21, -38, -39, -30, -31, -13, -31, -36, -34, -42), 'K': ( 4, 54, 47, -99, -99, 60, 83, -62, -32, 10, 55, 56, 56, 55, 10, 3, -62, 12, -57, 44, -67, 28, 37, -31, -55, 50, 11, -4, -19, 13, 0, -49, -55, -43, -52, -28, -51, -47, -8, -50, -47, -42, -43, -79, -64, -32, -29, -32, -4, 3, -14, -50, -57, -18, 13, 4, 17, 30, -3, -14, 6, -1, 40, 18), } # Pad tables and join piece and pst dictionaries for k, table in pst.items(): padrow = lambda row: (0,) + tuple(x + piece[k] for x in row) + (0,) pst[k] = sum((padrow(table[i * 8 : i * 8 + 8]) for i in range(8)), ()) pst[k] = (0,) * 20 + pst[k] + (0,) * 20 ############################################################################### # Global constants ############################################################################### # Our board is represented as a 120 character string. The padding allows for # fast detection of moves that don't stay within the board. A1, H1, A8, H8 = 91, 98, 21, 28 initial = ( " \n" # 0 - 9 " \n" # 10 - 19 " rnbqkbnr\n" # 20 - 29 " pppppppp\n" # 30 - 39 " ........\n" # 40 - 49 " ........\n" # 50 - 59 " ........\n" # 60 - 69 " ........\n" # 70 - 79 " PPPPPPPP\n" # 80 - 89 " RNBQKBNR\n" # 90 - 99 " \n" # 100 -109 " \n" # 110 -119 ) # Lists of possible moves for each piece type. N, E, S, W = -10, 1, 10, -1 directions = { "P": (N, N+N, N+W, N+E), "N": (N+N+E, E+N+E, E+S+E, S+S+E, S+S+W, W+S+W, W+N+W, N+N+W), "B": (N+E, S+E, S+W, N+W), "R": (N, E, S, W), "Q": (N, E, S, W, N+E, S+E, S+W, N+W), "K": (N, E, S, W, N+E, S+E, S+W, N+W) } # Mate value must be greater than 8*queen + 2*(rook+knight+bishop) # King value is set to twice this value such that if the opponent is # 8 queens up, but we got the king, we still exceed MATE_VALUE. # When a MATE is detected, we'll set the score to MATE_UPPER - plies to get there # E.g. Mate in 3 will be MATE_UPPER - 6 MATE_LOWER = piece["K"] - 10 * piece["Q"] MATE_UPPER = piece["K"] + 10 * piece["Q"] # Constants for tuning search QS = 40 QS_A = 140 EVAL_ROUGHNESS = 15 # minifier-hide start opt_ranges = dict( QS = (0, 300), QS_A = (0, 300), EVAL_ROUGHNESS = (0, 50), ) # minifier-hide end ############################################################################### # Chess logic ############################################################################### Move = namedtuple("Move", "i j prom") class Position(namedtuple("Position", "board score wc bc ep kp")): """A state of a chess game board -- a 120 char representation of the board score -- the board evaluation wc -- the castling rights, [west/queen side, east/king side] bc -- the opponent castling rights, [west/king side, east/queen side] ep - the en passant square kp - the king passant square """ def gen_moves(self): # For each of our pieces, iterate through each possible 'ray' of moves, # as defined in the 'directions' map. The rays are broken e.g. by # captures or immediately in case of pieces such as knights. for i, p in enumerate(self.board): if not p.isupper(): continue for d in directions[p]: for j in count(i + d, d): q = self.board[j] # Stay inside the board, and off friendly pieces if q.isspace() or q.isupper(): break # Pawn move, double move and capture if p == "P": if d in (N, N + N) and q != ".": break if d == N + N and (i < A1 + N or self.board[i + N] != "."): break if ( d in (N + W, N + E) and q == "." and j not in (self.ep, self.kp, self.kp - 1, self.kp + 1) #and j != self.ep and abs(j - self.kp) >= 2 ): break # If we move to the last row, we can be anything if A8 <= j <= H8: for prom in "NBRQ": yield Move(i, j, prom) break # Move it yield Move(i, j, "") # Stop crawlers from sliding, and sliding after captures if p in "PNK" or q.islower(): break # Castling, by sliding the rook next to the king if i == A1 and self.board[j + E] == "K" and self.wc[0]: yield Move(j + E, j + W, "") if i == H1 and self.board[j + W] == "K" and self.wc[1]: yield Move(j + W, j + E, "") def rotate(self, nullmove=False): """Rotates the board, preserving enpassant, unless nullmove""" return Position( self.board[::-1].swapcase(), -self.score, self.bc, self.wc, 119 - self.ep if self.ep and not nullmove else 0, 119 - self.kp if self.kp and not nullmove else 0, ) def move(self, move): i, j, prom = move p, q = self.board[i], self.board[j] put = lambda board, i, p: board[:i] + p + board[i + 1 :] # Copy variables and reset ep and kp board = self.board wc, bc, ep, kp = self.wc, self.bc, 0, 0 score = self.score + self.value(move) # Actual move board = put(board, j, board[i]) board = put(board, i, ".") # Castling rights, we move the rook or capture the opponent's if i == A1: wc = (False, wc[1]) if i == H1: wc = (wc[0], False) if j == A8: bc = (bc[0], False) if j == H8: bc = (False, bc[1]) # Castling if p == "K": wc = (False, False) if abs(j - i) == 2: kp = (i + j) // 2 board = put(board, A1 if j < i else H1, ".") board = put(board, kp, "R") # Pawn promotion, double move and en passant capture if p == "P": if A8 <= j <= H8: board = put(board, j, prom) if j - i == 2 * N: ep = i + N if j == self.ep: board = put(board, j + S, ".") # We rotate the returned position, so it's ready for the next player return Position(board, score, wc, bc, ep, kp).rotate() def value(self, move): i, j, prom = move p, q = self.board[i], self.board[j] # Actual move score = pst[p][j] - pst[p][i] # Capture if q.islower(): score += pst[q.upper()][119 - j] # Castling check detection if abs(j - self.kp) < 2: score += pst["K"][119 - j] # Castling if p == "K" and abs(i - j) == 2: score += pst["R"][(i + j) // 2] score -= pst["R"][A1 if j < i else H1] # Special pawn stuff if p == "P": if A8 <= j <= H8: score += pst[prom][j] - pst["P"][j] if j == self.ep: score += pst["P"][119 - (j + S)] return score ############################################################################### # Search logic ############################################################################### # lower <= s(pos) <= upper Entry = namedtuple("Entry", "lower upper") class Searcher: def __init__(self): self.tp_score = {} self.tp_move = {} self.history = set() self.nodes = 0 def bound(self, pos, gamma, depth, can_null=True): """ Let s* be the "true" score of the sub-tree we are searching. The method returns r, where if gamma > s* then s* <= r < gamma (A better upper bound) if gamma <= s* then gamma <= r <= s* (A better lower bound) """ self.nodes += 1 # Depth <= 0 is QSearch. Here any position is searched as deeply as is needed for # calmness, and from this point on there is no difference in behaviour depending on # depth, so so there is no reason to keep different depths in the transposition table. depth = max(depth, 0) # Sunfish is a king-capture engine, so we should always check if we # still have a king. Notice since this is the only termination check, # the remaining code has to be comfortable with being mated, stalemated # or able to capture the opponent king. if pos.score <= -MATE_LOWER: return -MATE_UPPER # Look in the table if we have already searched this position before. # We also need to be sure, that the stored search was over the same # nodes as the current search. entry = self.tp_score.get((pos, depth, can_null), Entry(-MATE_UPPER, MATE_UPPER)) if entry.lower >= gamma: return entry.lower if entry.upper < gamma: return entry.upper # Let's not repeat positions. We don't chat # - at the root (can_null=False) since it is in history, but not a draw. # - at depth=0, since it would be expensive and break "futility pruning". if can_null and depth > 0 and pos in self.history: return 0 # Generator of moves to search in order. # This allows us to define the moves, but only calculate them if needed. def moves(): # First try not moving at all. We only do this if there is at least one major # piece left on the board, since otherwise zugzwangs are too dangerous. # FIXME: We also can't null move if we can capture the opponent king. # Since if we do, we won't spot illegal moves that could lead to stalemate. # For now we just solve this by not using null-move in very unbalanced positions. # TODO: We could actually use null-move in QS as well. Not sure it would be very useful. # But still.... We just have to move stand-pat to be before null-move. #if depth > 2 and can_null and any(c in pos.board for c in "RBNQ"): #if depth > 2 and can_null and any(c in pos.board for c in "RBNQ") and abs(pos.score) < 500: if depth > 2 and can_null and abs(pos.score) < 500: yield None, -self.bound(pos.rotate(nullmove=True), 1 - gamma, depth - 3) # For QSearch we have a different kind of null-move, namely we can just stop # and not capture anything else. if depth == 0: yield None, pos.score # Look for the strongest ove from last time, the hash-move. killer = self.tp_move.get(pos) # If there isn't one, try to find one with a more shallow search. # This is known as Internal Iterative Deepening (IID). We set # can_null=True, since we want to make sure we actually find a move. if not killer and depth > 2: self.bound(pos, gamma, depth - 3, can_null=False) killer = self.tp_move.get(pos) # If depth == 0 we only try moves with high intrinsic score (captures and # promotions). Otherwise we do all moves. This is called quiescent search. val_lower = QS - depth * QS_A # Only play the move if it would be included at the current val-limit, # since otherwise we'd get search instability. # We will search it again in the main loop below, but the tp will fix # things for us. if killer and pos.value(killer) >= val_lower: yield killer, -self.bound(pos.move(killer), 1 - gamma, depth - 1) # Then all the other moves for val, move in sorted(((pos.value(m), m) for m in pos.gen_moves()), reverse=True): # Quiescent search if val < val_lower: break # If the new score is less than gamma, the opponent will for sure just # stand pat, since ""pos.score + val < gamma === -(pos.score + val) >= 1-gamma"" # This is known as futility pruning. if depth <= 1 and pos.score + val < gamma: # Need special case for MATE, since it would normally be caught # before standing pat. yield move, pos.score + val if val < MATE_LOWER else MATE_UPPER # We can also break, since we have ordered the moves by value, # so it can't get any better than this. break yield move, -self.bound(pos.move(move), 1 - gamma, depth - 1) # Run through the moves, shortcutting when possible best = -MATE_UPPER for move, score in moves(): best = max(best, score) if best >= gamma: # Save the move for pv construction and killer heuristic if move is not None: self.tp_move[pos] = move break # Stalemate checking is a bit tricky: Say we failed low, because # we can't (legally) move and so the (real) score is -infty. # At the next depth we are allowed to just return r, -infty <= r < gamma, # which is normally fine. # However, what if gamma = -10 and we don't have any legal moves? # Then the score is actaully a draw and we should fail high! # Thus, if best < gamma and best < 0 we need to double check what we are doing. # We will fix this problem another way: We add the requirement to bound, that # it always returns MATE_UPPER if the king is capturable. Even if another move # was also sufficient to go above gamma. If we see this value we know we are either # mate, or stalemate. It then suffices to check whether we're in check. # Note that at low depths, this may not actually be true, since maybe we just pruned # all the legal moves. So sunfish may report "mate", but then after more search # realize it's not a mate after all. That's fair. # This is too expensive to test at depth == 0 if depth > 2 and best == -MATE_UPPER: flipped = pos.rotate(nullmove=True) # Hopefully this is already in the TT because of null-move in_check = self.bound(flipped, MATE_UPPER, 0) == MATE_UPPER best = -MATE_LOWER if in_check else 0 # Table part 2 if best >= gamma: self.tp_score[pos, depth, can_null] = Entry(best, entry.upper) if best < gamma: self.tp_score[pos, depth, can_null] = Entry(entry.lower, best) return best def search(self, history): """Iterative deepening MTD-bi search""" self.nodes = 0 self.history = set(history) self.tp_score.clear() gamma = 0 # In finished games, we could potentially go far enough to cause a recursion # limit exception. Hence we bound the ply. We also can't start at 0, since # that's quiscent search, and we don't always play legal moves there. for depth in range(1, 1000): # The inner loop is a binary search on the score of the position. # Inv: lower <= score <= upper # 'while lower != upper' would work, but it's too much effort to spend # on what's probably not going to change the move played. lower, upper = -MATE_LOWER, MATE_LOWER while lower < upper - EVAL_ROUGHNESS: score = self.bound(history[-1], gamma, depth, can_null=False) if score >= gamma: lower = score if score < gamma: upper = score yield depth, gamma, score, self.tp_move.get(history[-1]) gamma = (lower + upper + 1) // 2 ############################################################################### # UCI User interface ############################################################################### def parse(c): fil, rank = ord(c[0]) - ord("a"), int(c[1]) - 1 return A1 + fil - 10 * rank def render(i): rank, fil = divmod(i - A1, 10) return chr(fil + ord("a")) + str(-rank + 1) hist = [Position(initial, 0, (True, True), (True, True), 0, 0)] #input = raw_input # minifier-hide start import sys, tools.uci tools.uci.run(sys.modules[__name__], hist[-1]) sys.exit() # minifier-hide end searcher = Searcher() while True: args = input().split() if args[0] == "uci": print("id name", version) print("uciok") elif args[0] == "isready": print("readyok") elif args[0] == "quit": break elif args[:2] == ["position", "startpos"]: del hist[1:] for ply, move in enumerate(args[3:]): i, j, prom = parse(move[:2]), parse(move[2:4]), move[4:].upper() if ply % 2 == 1: i, j = 119 - i, 119 - j hist.append(hist[-1].move(Move(i, j, prom))) elif args[0] == "go": wtime, btime, winc, binc = [int(a) / 1000 for a in args[2::2]] if len(hist) % 2 == 0: wtime, winc = btime, binc think = min(wtime / 40 + winc, wtime / 2 - 1) start = time.time() move_str = None for depth, gamma, score, move in Searcher().search(hist): # The only way we can be sure to have the real move in tp_move, # is if we have just failed high. if score >= gamma: i, j = move.i, move.j if len(hist) % 2 == 0: i, j = 119 - i, 119 - j move_str = render(i) + render(j) + move.prom.lower() print("info depth", depth, "score cp", score, "pv", move_str) if move_str and time.time() - start > think * 0.8: break print("bestmove", move_str or '(none)') 这段代码需要数据训练模型吗
最新发布
11-12
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值