程设竞赛中,选手按题数排名,如果题数一样,要看罚时。
罚时 = 从开始到通过题目的时间 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");
}