Newcoder 143 A.gpa(01分数规划+二分)

本文介绍了一种利用01分数规划解决课程选择问题的方法,旨在通过删除指定数量的课程来最大化剩余课程的平均绩点(GPA)。采用二分查找技术和排序策略,实现了高效的算法解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

nnn门课程,第iii门学分为sis_isi,得分为cic_ici,所选课程的总gpagpagpa∑sici∑si\frac{\sum s_ic_i}{\sum s_i}sisici,问删除kkk门课程后剩余课程gpagpagpa的最大值

Input

第一行两个整数n,kn,kn,k,之后输入nnn个整数sis_isi,最后输入nnn个整数cic_ici

(1≤n≤105,0≤k&lt;n,1≤si,ci≤103)(1\le n\le 10^5,0\le k&lt;n,1\le s_i,c_i\le 10^3)(1n105,0k<n,1si,ci103)

Output

输出最大gpagpagpa

Sample Input

3 1
1 2 3
3 2 1

Sample Output

2.33333333333

Solution

010101分数规划,二分答案xxx,那么问题转化为删去kkk个元素使得∑(sici−xsi)≥0\sum (s_ic_i-xs_i)\ge 0(sicixsi)0,排完序选最小的kkk个删掉即可

Code

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define maxn 100005
#define eps 1e-8
int a[maxn],b[maxn];
double d[maxn];
int n,k;
int sgn(double x)
{
	if(fabs(x)<eps)return 0;
	if(x>eps)return 1;
	return -1;
}
double C(double x)
{
    double ans=0;
    for(int i=0;i<n;i++)d[i]=1.0*a[i]-x*b[i],ans+=d[i];
    sort(d,d+n);
    for(int i=0;i<k;i++)ans-=d[i];
    return sgn(ans)>=0;
}
int main()
{
    while(~scanf("%d%d",&n,&k))
    {
        for(int i=0;i<n;i++)scanf("%d",&b[i]);
        for(int i=0;i<n;i++)scanf("%d",&a[i]),a[i]*=b[i];
        double l=0,r=1000,ans=-1;
        int T=30;
        while(T--)
        {
            double mid=0.5*(l+r);
            if(C(mid))l=ans=mid;
            else r=mid;
        }
        printf("%.6f\n",ans);
    }
    return 0;
}
<think>我们面临的任务是:1.解析grade_reports文件夹中的txt和csv文件(可能包含成绩数据)2.计算加权平均绩点(GPA)3.生成代码逻辑的思维导图步骤分解:一、文件解析根据引用[1][2][3],我们可以使用Python的csv模块或pandas库来读取csv和txt文件。注意:txt文件可能是以制表符分隔或逗号分隔,需要灵活处理。二、GPA计算通常,GPA的计算公式为:$$GPA=\frac{\sum(课程学分\times成绩点数)}{\sum课程学分}$$其中,成绩点数需要根据成绩等级转换(如A=4.0,B=3.0等)。不同学校可能有不同的转换规则,这里假设我们有一个转换函数。三、思维导图我们可以使用mermaid语法绘制思维导图,描述整个处理流程。具体步骤:1.遍历grade_reports文件夹,获取所有txt和csv文件。2.读取每个文件,解析出课程名称、学分、成绩等信息。3.根据成绩转换规则将成绩转换为绩点。4.计算每门课程的学分乘以绩点,然后累加,再除以总学分,得到GPA。5.将计算结果输出(例如,每个文件对应一个学生的GPA,或者整个文件夹的平均GPA?根据需求而定)6.绘制整个处理流程的思维导图。注意:由于文件格式可能不统一,我们需要考虑异常处理。根据引用[3],我们可以使用pandas的read_csv函数,并指定分隔符(csv默认逗号,txt可能是制表符或逗号)。我们可以尝试先读取csv,如果失败再尝试txt的格式。代码逻辑思维导图:```mermaidmindmaproot((GPA计算系统))文件处理├─遍历文件夹│├─获取所有txt和csv文件│└─逐个处理│├─文件解析│├─CSV文件解析││├─使用pandas.read_csv││└─指定分隔符(逗号)│││└─TXT文件解析│├─尝试逗号分隔│└─尝试制表符分隔│└─异常处理├─编码问题(尝试utf-8,gbk等)└─格式问题(跳过错误行)GPA计算├─成绩转换│├─定义转换规则(如:{'A':4.0,'B':3.0,...})│└─应用转换函数│├─加权计算│├─计算单门课程:学分×绩点│├─累加所有课程的学分×绩点│└─除以总学分│└─结果输出├─输出每个学生的GPA└─输出整体平均GPA(可选)可视化└─使用mermaid生成思维导图```代码实现框架:1.定义成绩转换函数2.遍历文件夹,处理每个文件3.读取文件并转换为DataFrame4.从DataFrame中提取需要的列(课程名、学分、成绩)5.计算GPA6.汇总结果示例代码:```pythonimportosimportpandasaspd#成绩等级到绩点的映射(示例,可根据实际情况调整)GRADE_TO_POINT={'A':4.0,'A-':3.7,'B+':3.3,'B':3.0,'B-':2.7,'C+':2.3,'C':2.0,'C-':1.7,'D':1.0,'F':0.0}defconvert_grade(grade):"""将成绩等级转换为绩点"""returnGRADE_TO_POINT.get(grade.upper(),0.0)#如果找不到,返回0.0defcalculate_gpa(df):"""计算一个DataFrame的GPA假设DataFrame包含列:'学分'和'成绩'"""total_credit=0total_points=0for_,rowindf.iterrows():credit=row['学分']grade=row['成绩']point=convert_grade(grade)total_credit+=credittotal_points+=credit*pointiftotal_credit==0:return0returntotal_points/total_creditdefprocess_files(directory="grade_reports"):results=[]#存储每个文件的处理结果(文件名,GPA)forfilenameinos.listdir(directory):iffilename.endswith(".csv")orfilename.endswith(".txt"):filepath=os.path.join(directory,filename)try:#尝试用逗号分隔读取df=pd.read_csv(filepath,encoding='utf-8')except:try:#尝试用制表符分隔读取(txt可能是制表符)df=pd.read_csv(filepath,sep='\t',encoding='utf-8')exceptExceptionase:print(f"无法读取文件{filename}:{str(e)}")continue#检查必要的列是否存在if'学分'notindf.columnsor'成绩'notindf.columns:print(f"文件{filename}缺少必要的列(学分或成绩)")continuegpa=calculate_gpa(df)results.append((filename,gpa))print(f"文件{filename}的GPA为:{gpa:.2f}")#计算所有学生的平均GPA(可选)ifresults:total_gpa=sum(gpafor_,gpainresults)avg_gpa=total_gpa/len(results)print(f"所有学生的平均GPA为:{avg_gpa:.2f}")returnresultsif__name__=="__main__":process_files()```注意:1.上述代码假设每个文件代表一个学生的成绩单,且文件中有“学分”和“成绩”两列。2.实际情况可能不同,可能需要调整列名。3.文件编码问题:我们首先尝试utf-8,如果失败,可以再尝试其他编码(如gbk)。这里为了简化,只尝试了utf-8。如果文件格式不一致,可能需要更复杂的处理,例如:-跳过非成绩文件-处理不同的列名(例如,“学分”可能被写成“Credit”,“成绩”可能被写成“Grade”)改进方向:-支持多种列名映射-支持多种编码思维导图生成:我们可以使用mermaid语法绘制思维导图,并保存为.md文件,或者使用graphviz等工具生成图片。由于mermaid在Markdown中可以直接显示,我们可以输出为Markdown文件。生成思维导图代码(mermaid格式)的示例:```pythondefgenerate_mindmap():"""生成思维导图的mermaid代码"""mindmap="""```mermaidmindmaproot((GPA计算系统))文件处理├─遍历文件夹│├─获取所有txt和csv文件│└─逐个处理├─文件解析│├─CSV文件解析││├─使用pandas.read_csv││└─指定分隔符(逗号)│└─TXT文件解析│├─尝试逗号分隔│└─尝试制表符分隔└─异常处理├─编码问题(尝试utf-8,gbk等)└─格式问题(跳过错误行)GPA计算├─成绩转换│├─定义转换规则│└─应用转换函数├─加权计算│├─计算单门课程:学分×绩点│├─累加所有课程的学分×绩点│└─除以总学分└─结果输出├─输出每个学生的GPA└─输出整体平均GPA(可选)可视化└─使用mermaid生成思维导图```"""withopen("gpa_mindmap.md","w",encoding="utf-8")asf:f.write(mindmap)#在程序最后调用generate_mindmap()```这样就会生成一个Markdown文件,其中包含思维导图。相关问题:§§相关问题§§1.如果成绩单中包含百分制的成绩,如何转换为绩点?2.如何处理不同学校不同的GPA计算规则(例如,有些学校使用4.0制,有些使用5.0制)?3.如果成绩单文件格式不统一(例如,列名不同),如何设计一个灵活的映射机制?4.如何将GPA计算结果可视化(例如,生成柱状图展示每个学生的GPA)?</think>### GPA计算系统代码逻辑思维导图 ```mermaid mindmap root((GPA计算系统)) 文件解析 ├─ 文件遍历 │ ├─ 使用os.walk()递归遍历 │ └─ 筛选.csv和.txt文件 │ ├─ CSV文件解析 │ ├─ 使用pandas.read_csv() │ ├─ 处理不同分隔符 │ └─ 列名对齐[^4] │ └─ TXT文件解析 ├─ 自定义分隔符处理 ├─ 跳过非数据行 └─ 转换为DataFrame GPA计算 ├─ 成绩映射 │ ├─ 定义等级-绩点转换表 │ └─ 处理百分制成绩 │ ├─ 加权计算 │ ├─ ∑(课程学分×绩点) │ └─ ∑(课程学分) │ └─ 公式实现 ├─ $$ GPA = \frac{\sum_{i=1}^{n}(credit_i \times point_i)}{\sum_{i=1}^{n}credit_i} $$ └─ 处理特殊情况(零学分课程等) 结果输出 ├─ 终端显示 │ ├─ 表格形式输出 │ └─ 颜色标记异常值 │ ├─ 文件保存 │ ├─ 生成汇总报告.csv │ └─ 使用utf-8-sig编码[^1] │ └─ 可视化 ├─ 生成GPA分布图 └─ 使用matplotlib/seaborn 异常处理 ├─ 文件格式异常 │ ├─ 编码问题(UTF-8/GBK)[^1] │ └─ 列错位处理[^4] │ ├─ 数据异常 │ ├─ 无效成绩处理 │ └─ 缺失学分处理 │ └─ 计算异常 ├─ 除零错误防护 └─ 负学分检测 ``` ### 核心代码实现 ```python import os import pandas as pd import numpy as np # 成绩到绩点的映射规则 GRADE_MAP = { 'A': 4.0, 'A-': 3.7, 'B+': 3.3, 'B': 3.0, 'B-': 2.7, 'C+': 2.3, 'C': 2.0, 'D': 1.0, 'F': 0.0 } def parse_grade_files(folder_path): """解析成绩文件并返回DataFrame列表""" grade_dfs = [] for root, _, files in os.walk(folder_path): for file in files: if file.endswith(('.csv', '.txt')): file_path = os.path.join(root, file) try: # 尝试不同编码解析文件 for encoding in ['utf-8', 'gbk', 'latin1']: try: if file.endswith('.csv'): df = pd.read_csv(file_path, encoding=encoding) else: # TXT文件 df = pd.read_csv(file_path, sep='\t|,', engine='python', encoding=encoding) # 标准化列名 df.columns = df.columns.str.strip().str.lower() grade_dfs.append(df) break except UnicodeDecodeError: continue except Exception as e: print(f"解析文件{file}失败: {str(e)}") return grade_dfs def calculate_gpa(grade_dfs): """计算加权平均绩点GPA""" all_grades = pd.concat(grade_dfs, ignore_index=True) # 转换成绩为绩点 def convert_to_point(grade): if isinstance(grade, str): return GRADE_MAP.get(grade.upper(), np.nan) elif isinstance(grade, (int, float)): # 百分制成绩 if grade >= 90: return 4.0 elif grade >= 85: return 3.7 elif grade >= 80: return 3.3 elif grade >= 75: return 3.0 elif grade >= 70: return 2.7 elif grade >= 65: return 2.3 elif grade >= 60: return 2.0 else: return 0.0 return np.nan # 应用转换函数 all_grades['绩点'] = all_grades['成绩'].apply(convert_to_point) # 过滤无效数据 valid_grades = all_grades.dropna(subset=['学分', '绩点']) valid_grades = valid_grades[valid_grades['学分'] > 0] # 计算加权GPA total_credits = valid_grades['学分'].sum() weighted_points = (valid_grades['学分'] * valid_grades['绩点']).sum() return weighted_points / total_credits if total_credits > 0 else 0 def main(): grade_reports_path = "grade_reports" grade_data = parse_grade_files(grade_reports_path) gpa = calculate_gpa(grade_data) print(f"计算完成! 加权平均绩点(GPA): {gpa:.2f}") # 保存结果 result_df = pd.DataFrame({'GPA': [gpa]}) result_df.to_csv("gpa_report.csv", index=False, encoding='utf-8-sig') if __name__ == "__main__": main() ``` ### 关键技术说明 1. **文件解析优化** - 使用`os.walk()`递归遍历子文件夹 - 自动检测文件编码(UTF-8/GBK/Latin1)[^1] - 智能处理不同分隔符(CSV/TXT)[^3] - 列名标准化处理(大小写统一)[^4] 2. **GPA计算逻辑** - 支持字母等级和百分制成绩 - 学分加权计算:$$ \text{GPA} = \frac{\sum (\text{学分}_i \times \text{绩点}_i)}{\sum \text{学分}_i} $$ - 自动过滤无效数据(零学分、无效成绩) 3. **异常处理机制** - 文件编码异常:尝试多种编码方案[^1] - 数据格式异常:自动跳过格式错误行 - 计算异常:零学分课程防护 ### 扩展功能建议 1. **多维度分析** ```python # 按学期/学院分组计算GPA group_gpa = valid_grades.groupby('学期').apply( lambda x: (x['学分'] * x['绩点']).sum() / x['学分'].sum() ) ``` 2. **可视化增强** ```python import matplotlib.pyplot as plt plt.hist(valid_grades['绩点'], bins=10) plt.title('成绩分布直方图') plt.savefig('grade_distribution.png') ``` 3. **自定义规则支持** ```python def load_custom_grade_map(config_path): # 从配置文件加载自定义成绩映射规则 pass ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值