洛谷题解——P2392:kkksc03考前临时抱佛脚

题目相关

题目链接

洛谷,https://www.luogu.com.cn/problem/P2392。

题目描述

这次期末考试,kkksc03 需要考 4 科。因此要开始刷习题集,每科都有一个习题集,分别有 s1​,s2​,s3​,s4​ 道题目,完成每道题目需要一些时间,可能不等 A1​,A2​,…,As1​​,B1​,B2​,…,Bs2​​,C1​,C2​,…,Cs3​​,D1​,D2​,…,Ds4​​。

kkksc03 有一个能力,他的左右两个大脑可以同时计算 2 道不同的题目,但是仅限于同一科。因此,kkksc03 必须一科一科的复习。

由于 kkksc03 还急着去处理洛谷的 bug,因此他希望尽快把事情做完,所以他希望知道能够完成复习的最短时间。

输入格式

本题包含 5 行数据:第 1 行,为四个正整数 s1​,s2​,s3​,s4​。

第 2 行,为 A1​,A2​,…,As1​​ 共 s1​ 个数,表示第一科习题集每道题目所消耗的时间。

第 3 行,为 B1​,B2​,…,Bs2​​ 共 s2​ 个数。

第 4 行,为 C1​,C2​,…,Cs3​​ 共 s3​ 个数。

第 5 行,为 D1​,D2​,…,Ds4​​ 共 s4​ 个数,意思均同上。

输出格式

输出一行,为复习完毕最短时间。

输入样例

1 2 1 3		
5
4 3
6
2 4 3

输出样例

20

数据范围

1 ≤ s1​, s2​, s3​, s4​ ≤ 20。

1 ≤ A1​,A2​,…,As1​​,B1​,B2​,…,Bs2​​,C1​,C2​,…,Cs3​​,D1​,D2​,…,Ds4​​≤60。

题目分析

看到求最短时间,我们立马对应到动态规划,本题用 01 背包来解是最优的。但是这次我们使用 DFS 来解题。

题意分析

就是有 4 门课,每门课有若干题目,每个题目有解题时间,但是我们可以同时同一门解两题,要求就最短的时间。妥妥的 DFS。

样例数据分析

根据样例数据,我们来模拟一下 DFS 的过程。有左脑和右脑可用。每次我们都先用左脑,再用右脑,也就是这样的搜索过程:先全部左脑(方案一)、左1左2(左脑解第一题和第二题)、左1右1、左2右1和右1有2,这么四种组合。

第一个科目

有一题,所以我们可以得到:

1、全左脑:耗时 5。

2、全右脑:耗时 5。

因此第一个科目的最小时间为 5 分钟。

第二个科目

有两题,所以我们可以得到:

1、全左脑:耗时 4+3=7。

2、左脑解题1,右脑解题2:耗时 max(4,3)=4。

3、左脑解题2,右脑解题1:耗时 max(3,4)=4。

4、全右脑:耗时 4+3=7。

因此第二个科目的最小时间为 4 分钟。

第三个科目

有一题,所以我们可以得到:

1、全左脑:耗时 6。

2、全右脑:耗时 6。

因此第三个科目的最小时间为 6 分钟。

第四个科目

有三题,所以我们可以得到:

1、全部左脑完成。这样耗时为 2+4+3=9。

2、左脑完成1、2题,右脑完成3题。这样耗时是 max(2+4, 3)=6。

3、左脑完成1、3题,右脑完成2题。这样耗时是 max(2+3, 4)=5。

4、左脑完成1题,右脑完成2、3题。这样耗时是 max(2, 4+3)=7。

5、左脑完成2 3题,右脑完成1题。这样耗时是 max(4+3, 2)=7。

6、左脑完成2题,右脑完成1、3题。这样耗时是 max(4, 3+2)=5。

7、左脑完成3题,右脑完成1、2题。这样耗时是 max(3, 2+4)=6。

8、全部右脑完成。这样耗时为 2+4+3=9。

因此第四个科目的最小时间为 5 分钟。

这里我们可以看到就是枚举题目分配给两个脑子所有可能组合。如果数据量大,我们可以使用减枝技巧。如上描述的过程,有一半是浪费的。

总时间

自然就是 5+4+6+5=20。

数据规模分析

根据题目描述,我们可以知道,一共 4 个科目,每个科目最多 20 个题目,因此最大的数据集为 4*20=80。也就是说,本题使用 DFS 搜索的时候,可以不需要剪枝。

每个题目耗时不会超过 60 分钟,那么最大的数据可能是 60*20*4=4800。因此用 int 这个数据类型足够。

算法思路

1、读入数据。

2、从第一个科目、第一个题目开始 DFS。

3、输出结果。

AC 参考代码

暴力 DFS 版本

#include 
#include 
#include 

using namespace std;

const int MAXN = 4;
const int MAXM = 22;
const int MAXT = 2;

int subjects[MAXN];//科目
int times[MAXN][MAXM];//时间
bool used[MAXN][MAXM];//是否复习完成
int Left;//左脑
int Right;//右脑
int minn;//某一门科目最小时间

//从第i门的第j题目开始复习
void dfs(int i, int j) {
    //判断本次搜索是否结束
    if (j>=subjects[i]) {
        minn = min(minn, max(Left, Right));
        return;
    }

    //左脑工作
    Left += times[i][j];
    dfs(i, j+1);
    Left -= times[i][j];

    //右脑工作
    Right += times[i][j];
    dfs(i, j+1);
    Right -= times[i][j];
}

int main() {
    for (int i=0; i<4; i++) {
        cin >> subjects[i];
    }
    for (int i=0; i<4; i++) {
        for (int j=0; j> times[i][j];
        }
    }

    //搜索
    int ans = 0;//最后的时间
    for (int i=0; i<4; i++) {
        Left=0;//左脑清零
        Right=0;//右脑清零
        minn = INT_MAX;//由于是要最小值
        dfs(i, 0);//从第i门的第一题开始复习
        ans += minn;
    }

    cout << ans << endl;

    return 0;
}

 

你可能感兴趣的:(OJ题解,#,洛谷题解,#,DFS)