[PTA] 5-28 Review of Programming Contest Rules (30分)

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


你可能感兴趣的:([PTA] 5-28 Review of Programming Contest Rules (30分))