POJ3104 Drying

本文介绍了一种利用二分枚举方法解决特定问题的算法思路。通过枚举最短时间并判断是否能够满足所有条件来找到最优解。算法实现过程中运用了数学公式进行精确计算,并通过迭代不断逼近正确答案。

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

题目链接:http://poj.org/problem?id=3104

这道题是我做的第一道二分枚举答案的题吧,可是实际上做的也不怎么样……

首先二分枚举答案,也就是最短时间,如果a[i]<t的话直接让它自然风干就行,如果大于t就计算使用几次风干器,假设x1是自然风干时间,x2是使用风干器的次数,那么x1+x2=t,x1+x2*k=a[i],两个方程联立,求出来使用的次数应该是(a[i]-t)/(k-1)的上界,所以把所有的使用散热器和自然风干的时间加到一起,和枚举的答案比较,然后继续二分就行。

#include <cstdio>
#include <cmath>
int maxt, t, a[100100], k, n;
bool check(int tt){
    double rt = 0;
    for (int i = 0; i < n; i++)
      if (a[i] > tt) rt += ceil(double(a[i] - tt) / double(k - 1));
    if (rt <= tt) return 1;
    else return 0;
}
void solve(){
    int l = 0, r = maxt;
    while (l <= r){
        int m = (l + r) >> 1;
        if (check(m)){
            if (!check(m - 1)){
                t = m; return;
            }
            r = m - 1;
        }
        else l = m + 1;
    }
}
int main(){
    while (~scanf("%d", &n)){
        maxt = 0;
        for (int i = 0; i < n; i++){
            scanf("%d", &a[i]);
            if (a[i] > maxt) maxt = a[i];
        }
        scanf("%d", &k);
        solve();
        printf("%d\n", t);
    }
    return 0;
}


<think>嗯,用户问的是POJ3104用C++怎么写。首先我得回忆一下这道题的内容。POJ3104应该是一个算法题,可能涉及到二分查找或者贪心策略。不过具体的题目内容我得先确认一下。 POJ3104的题目大意是说,有n件衣服,每件衣服有ai滴水。现在用烘干机来烘干,每分钟可以选择一件衣服用烘干机,这样能烘干k滴水,而自然晾干每分钟只能烘干1滴。但烘干机一次只能处理一件衣服,其他衣服在那一分钟只能自然晾干。问最少需要多少分钟才能把所有衣服烘干。对吧? 那这个问题正确的解法应该是用二分查找。因为我们需要找到最小的分钟数,假设这个分钟数是mid。对于每件衣服,如果ai <= mid,那自然晾干就行。但如果ai > mid,就需要使用烘干机。这时候,计算用烘干机的次数x,满足ai - x*k <= mid -x,因为每次烘干机使用会多减少(k-1)滴水。所以x >= (ai - mid)/(k-1)。这里需要注意除法向上取整的问题。然后将所有需要的x加起来,如果总和超过mid,则mid太小,需要增大下界,反之可以尝试缩小上界。 不过这里有个特殊情况,当k=1的时候,因为k-1=0,这时候烘干机和自然晾干的效果一样,所以只能自然晾干,所需时间就是最大ai的值。 接下来,如何用C++实现呢?首先读取n,然后读取每个ai,接着读取k。然后进行二分查找。左边界是1,右边界是最大的ai。每次计算mid,然后判断是否可行。需要注意的是,当k=1的时候要单独处理,否则计算的时候会出现除以0的情况。 可能的代码结构大致如下: 读取输入,保存到数组a中。 计算最大的ai作为初始右边界。 如果k=1,直接输出max_ai。 否则,进行二分查找: left = 1, right = max_ai while left < right: mid = (left + right) / 2 计算总需要的烘干次数sum for每个ai: if ai > mid: sum += ceil((ai - mid) / (k - 1)) if sum <= mid: right = mid else: left = mid + 1 输出left 这里需要注意的是,计算(ai - mid)的时候,如果这个值是负数的话不需要处理。另外,ceil可以用整数运算来实现,例如 (ai - mid + k - 2) / (k -1)。 测试一下边界情况,比如当k=1的时候是否正确。另外,当所有ai都不需要烘干机的情况,比如所有ai都<=mid,这时候sum是0,所以可以满足。 还有可能出现的问题是在计算sum的时候,可能会溢出,但题目中的数据范围可能不会太大,所以用long long可能更安全。不过POJ的数据范围可能需要看题目具体要求。假设ai的范围在1e9的话,用long long更合适。 所以代码中变量sum应该用long long类型,防止累加时溢出。 综上,C++代码的大体框架应该是这样的。需要处理k=1的特殊情况,二分查找的条件判断,以及计算烘干次数时的向上取整。</think>POJ3104 题目要求用高效方法烘干衣服,下面详细介绍解题思路和C++实现: ### 题目分析 **问题描述**: - $n$件衣服,每件初始含水量为$a_i$ - 每分钟可选择**1件**衣服用烘干机(每秒减少$k$滴水),其余衣服自然晾干(每秒减少$1$滴) - 求烘干所有衣服的**最短时间** **关键观察**: 1. 烘干机使用策略影响总时间 2. 直接模拟会超时,需用**二分法**优化时间复杂度 ### 算法思路 1. **二分查找答案**: - 最小时间范围:$left=1$, $right=\text{max}(a_i)$ - 对每个候选时间$mid$,检查是否可行 2. **可行性判断**: - 对每件衣服$a_i$: - 若$a_i \leq mid$:自然晾干即可 - 若$a_i > mid$:需使用烘干机,计算最少使用次数 $$\text{烘干次数} \geq \lceil \frac{a_i - mid}{k-1} \rceil$$ - 总烘干次数$\leq mid$时才合法(每分钟最多用1次烘干机) ### C++代码实现 ```cpp #include <iostream> #include <vector> #include <algorithm> using namespace std; typedef long long ll; int main() { int n, k; cin >> n; vector<int> a(n); for(int i=0; i<n; ++i) cin >> a[i]; cin >> k; int max_a = *max_element(a.begin(), a.end()); if(k == 1) { // 特殊情况处理 cout << max_a << endl; return 0; } ll left = 1, right = max_a; while(left < right) { ll mid = (left + right) / 2; ll sum = 0; for(int ai : a) { if(ai > mid) { // 计算ceil((ai - mid)/(k-1)) sum += (ai - mid + k-2) / (k-1); if(sum > mid) break; // 提前终止 } } if(sum <= mid) right = mid; else left = mid + 1; } cout << left << endl; return 0; } ``` ### 代码解析 1. **输入处理**:读取衣服数量和含水量 2. **特判$k=1$**:此时烘干机无效,直接输出最大含水量 3. **二分框架**: - 每次计算中点$mid$ - 统计所需烘干机总次数 - 根据总次数调整搜索区间 4. **关键计算**: - 使用整数技巧实现向上取整,避免浮点误差 - 提前终止循环优化效率 ### 复杂度分析 - **时间复杂度**:$O(n \log C)$,其中$C$为最大含水量 - **空间复杂度**:$O(n)$存储含水量数据 此解法能够高效处理题目中的大规模数据,通过二分将问题转化为可行性验证,避免了直接模拟的低效。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值