习题加餐 9 1.最快洗车时间

该博客探讨了小蓝洗车行如何在有两台洗车器的情况下,通过动态规划找到洗完所有车辆的最短时间。博主首先尝试贪心算法,发现无法得到最优解,然后转向动态规划解决方案,解释了算法设计和状态转移过程,并提供了C++代码实现。

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

 

1.最快洗车时间
问题描述
小蓝开了洗车行,有n辆车需要清洗,第i辆车清洗需要t;分钟。小蓝购买了两台自动洗车器,可以同时清洗车辆。但是由于两台洗车器共用一个电源,所以必须所有车辆都清洗完毕后才能关闭电源。
请问从第一辆车开始清洗后,忽略洗车之外的时间,至少需要多长时间才能关闭电源?
输入格式
第一行输入一个整数n表示需要清洗的车的数量。
第二行输入n个整数ti,表示每台车的洗车时间。数据范围保证:1≤n≤100,1≤ti≤1000。
输出格式
输出一个答案,表示最少需要的时间。
样例输入
3
123
样例输出
3
说明
样例中第1台车和第2台车在一个自动洗车器清洗,第3辆车在另外一台洗车器清洗,总共需要3分钟。

我的答案:贪心错了不能得到最优解结果答案错了

一、信息

题目要求计算洗完所有车辆所需的最短时间,小蓝有两台可以同时工作的洗车器。输入包括车辆数量 n 和每辆车的洗车时间列表 ti。我们的目标是最优地分配这些洗车任务到两台洗车器上,以最小化完成所有任务所需的时间。

二、分析

  • 作用和思考过程:问题的关键在于如何将车辆的洗车时间分配到两台洗车器上,使得耗时最长的洗车器的工作时间最短。
  • 分析过程:这是一个NP完全问题,一种有效的启发式方法是贪心算法,尽量保持两台洗车器的工作时间接近。
  • 样例分析:以样例为例,输入3辆车,洗车时间为1、2、3分钟。将时间最长的车辆优先分配到当前工作时间最短的洗车器上,结果是两台洗车器的工作时间尽可能接近。

三、算法设计

使用一个简单的贪心策略:

  1. 将洗车时间从大到小排序。
  2. 初始化两台洗车器的工作时间为0。
  3. 遍历排序后的洗车时间,总是将车辆分配给当前工作时间最短的洗车器。
  4. 最终结果为两台洗车器中较长的工作时间。

四、代码实现(用C++)

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
    int n;
    cin >> n;
    vector<int> washTimes(n);
    for (int i = 0; i < n; i++) {
        cin >> washTimes[i];
    }
    // 从大到小排序洗车时间
    sort(washTimes.begin(), washTimes.end(), greater<int>());

    int washer1 = 0, washer2 = 0;
    for (int time : washTimes) {
        if (washer1 <= washer2) {
            washer1 += time;
        } else {
            washer2 += time;
        }
    }
    
    cout << max(washer1, washer2) << endl;
    return 0;
}

五、实现代码过程中可能遇到的问题

  1. 不正确的排序方法导致非最优洗车时间分配。
  2. 错误地处理输入输出可能导致格式错误。
  3. 没有考虑所有边界情况,比如只有一辆车时。

六、Debug

  • 确保洗车时间正确输入和处理。
  • 检查边界情况,如 n=1。
  • 在多种测试情况下运行代码,确保输出正确。

正确答案:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> PII;
#define pb(s) push_back(s)
#define sz(s) ((int)s.size())
#define x first
#define y second
#define ms(s,x) memset(s, x, sizeof(s))
#define all(s) s.begin(),s.end()
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const int N = 110;
const int M = 101000;
int n;
int a[N];
bool f[N][M];
void solve()
{
    cin >> n;
    for (int i = 1; i <= n; ++i) cin >> a[i];
    int m = accumulate(a + 1, a + n + 1 , 0);
    f[0][0] = true;
    for (int i = 1; i <= n; ++i) {
        for (int j = 0; j <= m; ++j) {
            f[i][j] = f[i - 1][j];
            if (a[i] <= j) f[i][j] |= f[i - 1][j - a[i]];
        }
    }
    int ans = m;
    for (int i = 0; i <= m; ++i) {
        if (f[n][i]) {
            ans = min(ans, max(i, m - i));
        }
    }
    cout << ans << '\n';
}
int main()
{
    ios_base :: sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << setiosflags(ios::fixed) << setprecision(2);
    int t = 1;
    while (t--)
    {
        solve();
    }
    return 0;
}

我的理解:

一、信息

我们有 n 辆车,每辆车的洗车时间为 t[i],需要分配到两台洗车器中,使得最后关闭电源的时间最短。

二、分析

  1. 作用:将问题转换为子集和问题有助于我们使用动态规划解决问题。
  2. 思考过程:我们首先计算所有车辆洗车时间的总和 S,目标是找出时间和最接近 S/2 的车辆子集。
  3. 分析过程:定义一个布尔型二维数组 f[i][j] 来表示只考虑前 i 辆车时,是否能选择一些车辆使得它们的洗车时间总和为 j。如果存在这样的车辆组合,f[i][j] 为真。
  4. 样例分析:转移方程表示我们可以选择不洗当前这辆车,即洗车时间总和不变,或者洗这辆车,洗车时间总和增加当前车的洗车时间。

三、算法设计

采用二维动态规划解决子集和问题:

  • 初始化一个布尔型数组 f[n+1][S+1],f[0][0] = true,表示没有车辆时,洗车时间总和为 0 是可能的。
  • 对于每辆车,更新状态 f[i][j]。如果 f[i-1][j] 为真(即不考虑当前这辆车时,已经可以组合出洗车时间为 j),则 f[i][j] 也为真;如果 j 大于等于当前车的洗车时间 a[i] 且 f[i-1][j-a[i]] 为真(即考虑当前这辆车,并且去掉这辆车的洗车时间后的时间总和可以被组合出),则 f[i][j] 也为真。
  • 状态更新完成后,从中间值 S/2 开始向两边查找第一个为真的 f[n][j],则最短的总洗车时间为 max(j, S-j)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏驰和徐策

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值