题解 P2088 【果汁店的难题】

· · 题解

话说这个题目没题解就算了,连个标签也不给.

起初我以为是区间dp,结果...(中间8点全WA,最后一点还T掉了)

为了对这道题宣泄不满,我祭出随机数大法...(AC两个点...)

其实这道题 模拟+贪心 就好了.

成功的第一步就是认真读题:

注意客人的请求是有序的,不能先s只榨o一种r果汁t!

模拟的话大家都是大佬,我就用队列和集合随便搞搞.

贪心的策略稍微难想一些:

每次遇到 新的果汁 并且 所有榨汁机相对不干净 的时候,

我们选择一个优先级最高的榨汁机清洗(榨汁机刚刚榨过的果汁,需要再次榨的时间越久优先级越高)

举个栗子:

两台榨汁机正在榨: 4 5 (号果汁)

客人还需要: 7 8 5 4 5 (号果汁)

这时我们肯定要清洗 榨4号的机器 来榨7,

再清洗7(因为之后不需要榨7了)来榨8,

榨5不用清洗,榨4清洗8,榨5,over.(清洗3次)

我最怕的就是类似"显而易见"这种话,只要不是水题,我的智商和5岁小孩没有区别.

所以我们来证一下贪心吧:

(以榨汁机刚刚榨果汁的编号作为榨汁机的编号)

设机器刚刚榨过果汁X ={x1,x2...xk},客人还需要果汁Y ={y1,y2...yn}.

若 y1 ∉ X 并且 xa ∉ Y,清洗xa是最优解之一;

若 y1 ∉ X 并且 X ⊆ Y,

令{x1,x2...xk}在Y中 第一次 出现的时间为{t1,t2...tk},

要榨 Y-X 中的果汁肯定要清洗至少一次,就像y1一样

当ta越大时则在Y中xa之前的X的元素越多,即清洗次数越少.

ta最大,Y中xa之前的X中的元素最多(为除开xa的所有X中的元素),

若不清洗xa,则有xb∈X会导致多清洗一次,所以清洗xa最优.

下面我把我的AC代码贴上,仅供参考.

#include <bits/stdc++.h>
using namespace std;
const int N = 110;
int k, n, ans = 0;
queue<int> pos[N];    //pos[i].表示要 i号果汁客人的位置 
set<int> machine;    //machine表示当前机器正在榨的果汁 
queue<int> juice;    //表示果汁请求队列 
void arrange(int x)
{
    juice.pop(), pos[x].pop();
    if (machine.find(x) == machine.end()) //如果没有找到合适的榨汁机就要清洗了 
    {
        ans++;
        int farthest = 0, best;
        for (set<int>::iterator it = machine.begin(); it != machine.end(); it++)
            if (pos[*it].empty()) //如果这个果汁之后都没有客人点了,就直接清洗 
            {
                machine.erase(*it), machine.insert(x);
                return ;
            }
            else if (farthest < pos[*it].front()) //找一个短时间不可能用到的榨汁机清洗 
                farthest = pos[*it].front(), best = *it;
        machine.erase(best), machine.insert(x);
    }
    return ;
}
int main()
{
    ios::sync_with_stdio(false);
    cin >>k >>n;
    for (int i = 1, x; i <= n; i++)
    {
        cin >>x;
        pos[x].push(i);    //类似桶排的方法存果汁请求的位置 
        juice.push(x);    //当前请求入队 
    }
    //在不清洗的情况下安排满k个榨汁机 
    while (machine.size() < k && !juice.empty())
    {
        int temp = juice.front();
        juice.pop(), pos[temp].pop();
        machine.insert(temp);
    }
    while (!juice.empty()) //如果还有果汁要榨就给安排榨汁机 
        arrange(juice.front());
    cout <<ans <<endl;
    return 0;
}