ADS-WK11-Review of Programming Contest Rules-回溯剪枝

本文介绍了ACM ICPC竞赛的计分规则,详细说明了总时间如何计算,并给出一个例子解释了解题顺序如何影响最终排名。你被要求编写一个程序,寻找最佳的解题顺序以提高赢得比赛的机会。输入规格包含竞赛小时数、问题数量及阅读所有问题所需的时间,输出应为最优解题顺序及其总时间。

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

【题目】

The ACM ICPC's rule of scoring is as the following:

A problem is solved when it is accepted by the judges. Teams are ranked according to the most problems solved. For the purposes of awards, or in determining qualifier(s) for the World Finals, teams who solve the same number of problems are ranked by least total time. The total time is the sum of the time consumed for each problem solved. The time consumed for a solved problem is the time elapsed from the beginning of the contest to the submittal of the accepted run plus 20 penalty minutes for every rejected run for that problem regardless of submittal time. There is no time consumed for a problem that is not solved.

For example, if one has the following contest record:

  • At the 100th minute submitted problem A, rejected;
  • At the 140th minute submitted problem B, rejected;
  • At the 150th minute submitted problem B, accepted;
  • At the 160th minute submitted problem C, accepted.

Then his total time = (150+20) + 160 = 330. Notice that it took him only 10 minutes to finish problem C. Assume that he spent 40 minutes on reading all the problems through, then if he could do problem C first and problem A last, his contest record might look like:

  • At the 50th minute submitted problem C, accepted;
  • At the 90th minute submitted problem B, rejected;
  • At the 100th minute submitted problem B, accepted;
  • At the 160th minute submitted problem A, rejected.

Then his total time would be 50 + (100+20) = 170. Hence the order of solving the problems will affect one's final rank.

Now suppose that you are in a one-person team. It will take you t0t0minutes to read all the problems through. Judging by your experience, you may estimate the minutes titi that you will take to solve problem ii. And more, the earlier you get one problem done, the more unlikely that you will make mistakes on programming. Assume that if a solution is first time submitted in the first hour (60 minutes inclusive), it will get accepted at once; if it is first time submitted in the second hour, it will be rejected once; if it is first time submitted in the third hour, it will be rejected twice; etc. You may also estimate the minutes didi for debugging problem ii every time it is rejected. For the sake of simplicity, let us assume that didi is fixed for each problem ii, and once you start working on a problem, you will keep submitting until it is accepted.

Your task is to write a program to find yourself the order of solving the problems which gives you the best chance of winning the contest.

Input Specification:

Each input file contains several test cases. For each test case, the 1st line contains 3 integers: the total number of contest hours H (0 < H  5), the total number of problems N (0 < N  9), and the time t0t0 (minutes) for you to read through all the problems at the beginning of the contest. The following N lines each contains a problem's name and a pair of positive integers titi and didi. A problem's name is a string of no more than 20 characters without any space. A negative H signals the end of input.

Output Specification:

For each test case, you are supposed to print to standard output the total time in a line in the format shown by the sample. Then print the names of the problems you will solve in the correct order, each name in a line. If there are several solutions, you must output the smallest sequence. A sequence of problems { i1i1i2i2, ... inin } is smaller than another sequence { j1j1j2j2, ... jnjn } means that there exists an integer KK between 1 and nn such that for every 1kK1k<K, we have ikjkik=jk, and iKjKiK<jK.


【代码】

#include <iostream>
#include <string.h>
#define MAXP 10
using namespace std;

int H=0,N,T0;
int T[MAXP],D[MAXP];//T:题目完成时间 D:题目debug时间
string problem_name[MAXP];
int fin_pro_No[MAXP];//按顺序记录完成的题目序号
bool pro_state[MAXP];//记录题目完成情况:true该题完成 false该题未完成
int final_num;
int final_pro_No[MAXP];
int final_totalTime;

void update_strategy(int num, int totalTime){
    //控制策略的选择
    if (num < final_num) return;//优先选择做出题数多的策略
    if (num == final_num && totalTime>=final_totalTime) return;//做出题数一样,选择时间少的
    //更新策略
    final_num = num;
    final_totalTime = totalTime;
    for (int i=0; i<num; i++) {
        final_pro_No[i]=fin_pro_No[i];
    }
}

//num:完成的题数
//usedTime:用掉的时间
//totalTime:成绩时间
void dfs(int num, int usedTime, int totalTime){
    
    int first_submit_time = usedTime + T[fin_pro_No[num]];
    int debug_times = (first_submit_time - 1)/60;
    int next_usedTime = first_submit_time + debug_times * D[fin_pro_No[num]];
    int next_totalTime = totalTime + next_usedTime + debug_times*20;
    
    if (next_usedTime <= H*60) {//规定时间内能成功提交本题
        num ++;
        if (num < N) {//还有未完成的题
            for (int i =0; i<N; i++) {//尝试每个可走的岔路
                if (!pro_state[i]) {
                    pro_state[i]=true;
                    fin_pro_No[num]=i;
                    dfs(num, next_usedTime, next_totalTime);
                    pro_state[i]=false;//===>剪枝
                    //不用num--,num是形参,每层的num都不一样
                }
            }
        }
        else update_strategy(num, next_totalTime);//无题可做。找到一种策略,回到上一层===>
    }
    else update_strategy(num, totalTime);//超时。找到一种策略,回到上一层===>
}

int main(){
    cin >> H;
    while (H>0) {
        cin >> N >> T0;
        for (int i=0; i<N; i++) {
            cin >> problem_name[i] >> T[i] >> D[i];
        }
        //变量初始化
        final_num = 0;
        final_totalTime = ~(1 << 31);
        memset(final_pro_No,0,sizeof(final_pro_No));
        memset(fin_pro_No, 0, sizeof(fin_pro_No));
        memset(pro_state, false, sizeof(pro_state));
        
        for (int i=0; i<N; i++) {
            pro_state[i]=true;
            fin_pro_No[0]=i;
            dfs(0, T0, 0);//用掉的时间为读题时间,成绩时间为0
            pro_state[i]=false;
        }
        
        cout << "Total Time = " << final_totalTime << endl;
        for (int i=0; i<final_num; i++) {
            cout << problem_name[final_pro_No[i]] << endl;
        }
        
        cin >> H;
    }
    
    return 0;
}

参考:http://blog.youkuaiyun.com/zccz14/article/details/51449748


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值