程设竞赛中,选手按题数排名,如果题数一样,要看罚时。
罚时 = 从开始到通过题目的时间 min + 错误次数 * 20min
如果没过,就不存在罚时。
我们假设一个人在一个小时内交的题目一次通过(包括60min),两个小时内错一次再过,三个小时内错两次后过,以此类推……
在刚开始的时候,他需要一定时间浏览完全部题目,一开始需要一定时间做题,做错后debug一定时间,如果一道题没做完,将一直做到做出为止。
假设对于每道题,做题时间一定,debug时间一定,求题目的最佳安排顺序,以获得最大的通过数和最少的罚时。
输入:
比赛小时数 题目数 浏览题目时间
题目名字1 做出时间 debug时间
题目名字2 做出时间 debug时间
……
输出:
最小罚时
做题顺序
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<string.h> #include<stdlib.h> int min;//记录最小时间 int max;//记录最多解题数 int time, num, t0; //比赛时间,题目总数,浏览题目时间 char c[12][22];//题目字符串 int visit[12];//是否记录过该题目 int t[12];//做出该题时间 int d[12];//debug时间 int path[12];//记录做题顺序(临时) int count;//记录层数 int index[12];//存储最终做题顺序结果 //current_time为当前时间(从比赛开始到现在过了多少分钟) //total_time是当前总罚时 //accepted_time是当前做出题数 void dfs(int i, int current_time, int total_time, int accepted_num) { if (i != -1) { path[count] = i;//记录题目 int first_submit_hour = (current_time + t[i]) / 60 + !!((current_time + t[i]) % 60); //计算第一次提交的小时数 if (first_submit_hour == 1) { //如果在一个小时内提交,则通过 current_time += t[i];//当前时间加上做这题的时间 total_time += current_time; //总时间加上当前时间 accepted_num++;//AC数加一 } else if (first_submit_hour > 1) { //如果超过1小时提交 int tmp = current_time + t[i] + (first_submit_hour - 1)*d[i]; //计算最终提交这道题的时间 if (tmp <= time * 60) {//如果没有超过比赛期限 current_time = tmp;//当前时间更新为提交这道题的时间 total_time += current_time + 20 * (first_submit_hour - 1); //总时间加上当前时间与罚时的总和 accepted_num++;//AC数加一 } else { //如果超过了比赛期限 if (accepted_num > max || accepted_num == max && total_time < min) { //如果有更多的解题数,或者有相同的解题数,但是有更短的总时间 max = accepted_num;//更新解题数 min = total_time;//更新总时间 for (int j = 1; j < count; j++) {//更新题目 index[j - 1] = path[j]; } } return; } } if (accepted_num == num) { //没有超过比赛期限,但是题目已全部解出 if (accepted_num > max || (accepted_num == max && total_time < min)) { //如果有更多的解题数,或者有相同的解题数,但是有更短的总时间 max = accepted_num;//更新解题数 min = total_time;//更新总时间 for (int j = 1; j <= count; j++) {//更新题目 index[j - 1] = path[j]; } return; } } //如果总时间超过了最小时间,而且解题数目还小于等于当前解题数,剪枝 //因为最多只有九个题目,所以这个剪枝可有可无 /* if (total_time > min && accepted_num <= max) { return; } */ } for (int i = 0; i < num; i++) {//遍历所有题目 if (visit[i] == 0) {//如果没有访问过 visit[i] = 1;//标记为访问 count++;//层数加一 dfs(i, current_time, total_time, accepted_num);//搜索 count--;//层数减一 visit[i] = 0;//退出后标记为未访问 } } } int main() { //freopen("test.txt", "r", stdin); while (scanf("%d", &time), time>0) { count = 0; size = 0; max = 0; memset(visit, 0, sizeof(visit)); min = 10000; scanf("%d %d", &num, &t0); for (int i = 0; i < num; i++) { scanf("%s %d %d", c[i], &t[i], &d[i]); } dfs(-1, t0, 0, 0); printf("Total Time = %d\n", min); for (int i = 0; i < max; i++) { printf("%s\n", c[index[i]]); } } //system("pause"); }