A公司的烦恼(贪心)

题目描述:

A公司的计算机管理系统受到千年虫病毒的攻击,因此A公司丢失了向MS公司做年终回报的数据。

A公司目前掌握的数据是MS公司每次公布的公司亏盈报表,而MS公司公布亏盈的方式与众不同,它么次都是将连续5个月的亏盈总和做一次性公布,因此A公司不知道每个月具体的亏盈状况。已知的情况是所有的盈利月的盈利固定为 s ,而亏损月的亏损固定为 d 。

写一个程序,确定MS公司是否盈利,若盈利的话,计算可能的盈利最大值。

输入:

输入为两个整数 s 和 d 。

输出:

对于每一组的输入数据,若盈利的话,那么输出可能盈利最大值;若亏损的话,输出 Deficit。

样例输入:

59 237

375 743

200000 849694

2500000 8000000

样例输出:

116

28

300612

 Deficit

 

 

分析:看题得知盈利月和亏损月各自的盈利和亏损是固定的,一年只有12个月,它又是每5个月做一次报告,那么一年撑死做两次报告,我们划分为前5个月和后5个月,由于盈利和亏损的值是个固定的,那么实质上前五个月和后五个月本质上是相同的,即后五个月是前五个月的一个复制罢了。关键是要如何安排亏损月和盈利月的位置,假设5个月至少亏损3个月,那么对前五个月来说,亏损的月份必定是3,4,5月份,为什么?前面分析过这两个5月本质是一样的,是前一个的重复,前五个月是ssddd,那后五个月也是是ssddd,剩下的月份就是ss了,达到最大利益,如果是dddss这种情况,那最后剩下的两个月份则为dd,这样无法达到最大利润,用贪心的思想合理排布亏损盈利情况即可解出此题。

 

 

 

#include <iostream>
using namespace std;
const int MAXN = 100005;
 
int temp[MAXN];
 
 
 
int main()
{
    int s, d;
    int i;
 
    while(cin >> s >> d)
    {
        int total = 0;
        for(i=1; i<=5; i++)
        {
            if(s * (5 - i) - d * i < 0)
            {
                break;                 //枚举出5个月中至少有i个亏损月
            }
        }
 
        //i == 5      dddddddddddd        此情况全年赤字
        //i == 4      sddddsddddsd
        //i == 3      ssdddssdddss
        //i == 2      sssddsssddss
        //i == 1      ssssdssssdss
        if(i == 4)
        {
            total = 3 * s - 9 * d;
        }
        else
        {
            total = (12 - 2 * i) * s - d * 2 * i;
        }
 
        if(i == 5 || total < 0)
        {
            cout << "Deficit" << endl;
        }
        else
        {
            cout << total << endl;
        }
    }
    return 0;
}

 

 

 

 

<think>嗯,用户的问题是关于如何分配学生到学校,使得估分和录取线的差值绝对值之和最小。这个问题听起来像是一个优化问题,可能需要用到匹配算法或者线性规划之类的。首先,我得明确问题的具体要求。 用户提到要最小化不满意程度的总和,也就是所有学生的估分和学校录取线差值的绝对值之和最小。这让我想到可能需要将学生和学校进行某种最优匹配。每个学生只能去一个学校,每个学校可能有名额限制。这时候,可能需要建立一个数学模型,把问题转化为数学表达式。 首先,我应该考虑问题的约束条件。比如,每个学生只能被分配到一个学校,每个学校有招生名额的限制。这看起来像是一个指派问题,或者运输问题。可能需要用到匈牙利算法,或者更高效的算法,尤其是当数据量大的时候。 不过,绝对值的存在会让问题变得非线性,处理起来可能比较麻烦。这时候,可能需要将绝对值转化为线性表达式。比如,对于每个学生和学校的配对,可以将差值的绝对值分解为两个非负变量,然后添加约束条件,这样问题就可以转化为线性规划问题。不过,线性规划可能需要使用特定的求解器,或者在某些情况下,可以用更简单的方法解决。 另外,可能要考虑学校的位置是否影响学生的分配,或者是否有其他因素,比如学生的偏好,但问题中只提到了估分和录取线的差值,所以可能不需要考虑这些因素。这时候,问题可以简化为一个带权重的二分图匹配问题,学生和学校作为二分图的两部分,边的权重是差值的绝对值,然后找到一种匹配方式,使得总权重最小,同时满足学校的名额限制。 这让我想到这可能是一个最小费用流问题。将学生和学校建模为图中的节点,学生节点连接到学校节点,边的容量为1,费用为对应的绝对值差值。然后,学校节点连接到汇点,边的容量为学校的名额。学生节点从源点流出,容量为1。这样,最小费用流就能找到总费用最小的分配方式。 或者,如果学校的名额是固定的,可能需要使用带权二分图匹配的算法,比如匈牙利算法的变种,或者更高效的算法。不过,当学校和学生数量较大时,可能需要更高效的算法,比如使用优先队列进行贪心匹配。 例如,先将学生按估分排序,学校也按录取线排序,然后按顺序分配,这样可能得到一个近似最优解。不过,这样的贪心方法是否总是最优的?可能不是,因为可能存在某些学生分配到更远的学校反而整体更优的情况。比如,如果两个学生的估分分别为500和510,而学校的录取线为505和515,那么贪心分配可能把500分学生分到505,510分分到515,总差值为5+5=10。但另一种分配方式可能是500分到505,510也到505,这样差值5+5=10,但假设第二个学校还有一个名额,那可能更好?不过这可能要看具体名额的限制。 所以贪心可能不总是最优,这时候就需要更精确的算法。而将问题转化为最小费用流可能更可靠,因为这是一个精确的解法,但计算复杂度可能较高,尤其是当学生和学校数量很大时。 另外,差分和前缀和的知识可能在这里用不上,但用户提到了参考内容中的差分是前缀和的逆运算,不确定是否有相关性。可能需要结合其他算法。 再考虑问题中的绝对值最小化总和,可以将其转化为线性规划问题。例如,对于每个学生i和学校j,定义一个变量x_ij,表示是否分配学生i到学校j。目标函数是Σ|x_ij*(s_i - t_j)|,其中s_i是学生估分,t_j是学校录取线。然后约束条件包括每个学生只能分配到一个学校,每个学校不超过其名额。由于绝对值的存在,可以将每个项分解为两个非负变量,比如u_ij和v_ij,使得s_i - t_j = u_ij - v_ij,然后目标函数变为Σ(u_ij + v_ij)。这样,问题就转化为线性规划,可以使用单纯形法等方法求解。不过,当问题规模较大时,这样的方法可能计算量很大。 不过,如果所有的学生和学校都是按照分数排序的,可能存在一种最优分配方式,即按顺序匹配学生到学校。例如,将学生和学校都按分数排序,然后依次分配,这可能达到最优。这种情况下,可以使用贪心算法,时间复杂度较低。但需要验证这种方法的正确性。 例如,假设学生按s_1 ≤ s_2 ≤ ... ≤ s_n,学校按t_1 ≤ t_2 ≤ ... ≤ t_m,那么将第一个学生分配到第一个学校,直到名额用完,再分配到下一个学校,以此类推。这种方法可能保证总差值最小。这可能类似于任务分配中的“贪心匹配”。 但需要验证是否存在反例。例如,学校A的录取线为100,名额2;学校B录取线200,名额1。三个学生,分数分别为90, 110, 210。按贪心分配,学生1到A(差10),学生2到A(差10),学生3到B(差10),总差30。但如果学生2分配到B,差90,学生3到B的话,但学校B只有一个名额,所以学生2不能分配到B。所以这种情况下贪心是正确的。或者另一个例子:学校A(100,名额1),学校B(150,名额1),学生分数120和130。按贪心分配,120到A(差20),130到B(差20),总差40。另一种分配方式,120到B(差30),130到A(差30),总差60,所以贪心更好。或者学生分数是140和160,学校A(150名额1),B(170名额1)。贪心分配140到A(差10),160到B(差10),总差20。如果交换的话,140到B差30,160到A差10,总差40。所以贪心更好。似乎按排序后的顺序分配是正确的。这种情况下,总差值可能最小。 这可能涉及到数学中的最优运输问题,当两个序列都排序后,按顺序匹配可以得到最优解。这可能需要数学证明。例如,假设两个数组都是升序排列,那么对应元素相减的绝对值之和是最小的。这个结论是否正确? 比如,有两个有序数组a1 ≤ a2,b1 ≤ b2,要配对成(a1,b1)(a2,b2),或者(a1,b2)(a2,b1)。哪一种的绝对值之和更小?假设a1=1, a2=3,b1=2, b2=4。顺序配对的话,差值是1和1,总和2。交叉配对的话,差值是3和1,总和4。所以顺序更好。另一个例子,a1=1, a2=4,b1=2, b2=3。顺序配对差1和1,总和2。交叉配对差2和0,总和也是2。这时候相等。但如果是a1=1, a2=5,b1=3, b2=4。顺序配对差2和1,总和3。交叉配对差3和0,总和3。相等。所以在这种情况下,可能顺序配对不一定总是更优,但有时候是相等的。不过,当存在多个元素时,是否按顺序配对能得到最小值? 这可能需要数学证明,比如根据排序不等式。绝对值函数是凸函数,所以可能在这种情况下,顺序配对能够使总和最小。因此,当学生和学校都按分数排序后,按顺序匹配可以最小化总差值。这可能就是贪心策略的有效性所在。 因此,算法的大致步骤可能是: 1. 将所有学生按估分升序排序。 2. 将所有学校按录取线升序排序。 3. 对每个学校,按排序后的顺序分配学生,直到名额填满。 4. 这样得到的总不满意程度总和可能最小。 但需要处理学校名额的问题。例如,当多个学校可能具有相同的录取线时,或者学生数量超过总名额时如何处理。但假设总名额等于学生数量,否则问题可能无解。或者需要处理这种情况。 此外,这种贪心方法是否正确,可能需要数学证明。例如,当两个序列都按升序排列时,进行顺序匹配是否可以得到最小的曼哈顿距离总和(即绝对值之和)。这似乎类似于在最优运输中的情况,当成本函数是凸的时候,顺序匹配可能最优。 假设这个结论成立,那么算法的实现步骤可以是: - 学生和学校都按分数排序。 - 为每个学校维护一个剩余名额计数器。 - 遍历排序后的学生列表,依次将每个学生分配到当前剩余名额未满且录取线最接近该生估分的学校。但这里可能需要更精确的分配方式,比如双指针法。 例如,学生和学校都排序后,用两个指针i(学生)和j(学校),将学生i分配到学校j,直到学校j的名额用完,然后j++。这样,可以确保每个学生分配到录取线最低且还有名额的学校。这可能得到最小的总差值。 例如,学生分数排序为s1 ≤ s2 ≤ ... ≤ sn,学校排序为t1 ≤ t2 ≤ ... ≤ tm。每个学校有k_j个名额。初始化j=0,然后对于每个学生i,找到第一个学校j,其t_j >= s_i,并且还有名额,或者前面的学校名额已满。这可能类似于归并排序的过程,或者双指针。 或者,更简单的方法是,将学校按录取线排序,并扩展为每个学校有k_j个位置,例如,学校A有2个名额,则视为两个虚拟学校,每个录取线相同。然后将所有学生和所有学校的虚拟位置排序,然后一一匹配。这可能类似于将问题转化为两个排序数组的匹配。 例如,将学校按录取线排序,并为每个学校生成k_j个相同的录取线节点。然后将所有学生的分数和所有生成的学校节点排序,然后一一对应匹配。这样得到的差值总和就是最小的。这种方法是否正确? 假设学生分数排序后为s_1 ≤ s_2 ≤ ... ≤ s_n,学校生成的节点排序后为t_1 ≤ t_2 ≤ ... ≤ t_n(假设总名额等于学生数),那么一一对应匹配,即s_i分配到t_i,此时总绝对值之和最小。这应该是成立的,因为对于两个有序序列,对应元素差的绝对值之和是最小的。例如,在数学中,这被称为最小绝对偏差的匹配,当两个序列都排序时,对应位置匹配可以得到最小值。 因此,算法可以将每个学校扩展为k_j个相同录取线的节点,然后将所有节点排序,与学生排序后的列表一一对应分配。这样得到的差值总和就是最小的。这种方法的时间复杂度取决于排序和扩展学校的过程。假设总共有M个学校名额,总学生数N=M。扩展学校可能需要O(M)的时间,排序学生和扩展后的学校列表需要O(N log N + M log M)时间,然后分配是O(N)时间。如果M和N很大,这可能可行,但需要处理大量数据的情况。 例如,如果有三个学校,录取线分别为500、550、600,名额分别为2、3、1。那么扩展后的学校列表是[500,500,550,550,550,600]。然后学生排序后的列表为s1, s2, s3, s4, s5, s6,一一对应分配,s1→500,s2→500,s3→550,s4→550,s5→550,s6→600。这样总差值就是各个学生与对应学校录取线的绝对值之和,此时总和应该最小。 这种方法似乎是可行的,但需要确保总学生数等于总名额数。如果学生数不等于总名额,可能需要调整问题,比如允许某些学校未招满,或者学生未被分配,但原问题可能假设学生和名额数匹配。 因此,算法的步骤可以总结为: 1. 将所有学校按照录取线升序排序,并为每个学校生成对应数量的位置(例如,录取线t_j出现k_j次)。 2. 将所有学生按估分升序排序。 3. 将扩展后的学校录取线列表合并并保持升序。 4. 将排序后的学生列表与扩展后的学校列表一一匹配,即第i个学生分配到第i个录取线位置。 5. 计算总差值。 这样得到的分配方案将总差值最小化。这种方法的时间复杂度主要由排序步骤决定,因此对于大规模数据是可行的。 此外,用户提供的参考内容中提到了视差计算中的WTA策略,即直接选择最优的匹配点。这里的最优分配可能也类似于这种策略,即在所有可能的选择中选择当前最优的,但需要系统性的方法确保全局最优。 总结来说,这个问题可以转化为两个有序序列的最优匹配问题,通过排序和一一对应分配来达到总差值最小。这种方法在数学上被证明是正确的,因此可以应用于此场景。</think>### 学生-学校最优匹配算法设计 #### 问题建模 将学生估分记为$s_i$,学校录取线记为$t_j$,每个学校名额为$k_j$。目标是最小化总差值: $$ \min \sum |s_i - t_j| $$ 需满足约束条件: 1. 每个学生分配到且仅分配到一个学校 2. 每个学校分配人数不超过$k_j$ #### 算法步骤 1. **数据预处理** - 对学生估分数组$S$进行升序排序 - 对学校按录取线升序排序,并扩展为包含所有名额的录取线数组$T_{ext}$(例如学校A有2个名额则生成两个相同元素) 2. **双指针匹配** 使用双指针分别指向已排序的学生数组和扩展后的录取线数组,实现一一对应匹配: ```python def allocate_students(students, schools): students_sorted = sorted(students) schools_expanded = [] for t, k in sorted(schools, key=lambda x: x[0]): schools_expanded.extend([t] * k) total_diff = 0 allocation = [] for s, t in zip(sorted(students_sorted), sorted(schools_expanded)): total_diff += abs(s - t) allocation.append((s, t)) return total_diff, allocation ``` 3. **复杂度分析** - 时间复杂度:$O(n \log n + m \log m)$,其中$n$为学生数,$m$为学校扩展后的总名额数 - 空间复杂度:$O(m)$ #### 数学证明 当两个序列都单调递增时,对应元素差的绝对值之和最小。设有序序列$a_1 \leq ... \leq a_n$和$b_1 \leq ... \leq b_n$,对任意排列$\sigma$有: $$ \sum_{i=1}^n |a_i - b_i| \leq \sum_{i=1}^n |a_i - b_{\sigma(i)}| $$ 该结论可由数学归纳法证明[^2]。 #### 应用示例 假设: - 学生估分:$[520, 480, 550, 510]$ - 学校数据:$(500, 2), (530, 1), (540, 1)$ 执行过程: 1. 扩展学校录取线:$[500, 500, 530, 540]$ 2. 排序后学生:$[480, 510, 520, 550]$ 3. 匹配结果:$(480→500), (510→500), (520→530), (550→540)$ 4. 总差值:$20+10+10+10=50$
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值