本题是一个侧重于数学证明的排序贪心问题,调度优化问题
核心思路
核心观察
这是一个经典的调度优化问题。关键在于:先送哪头奶牛会影响后续奶牛的等待时间。
-
如果先送奶牛 A 再送奶牛 B:
- 奶牛 A 的等待时间 = 0(立即被送走)
- 奶牛 B 的等待时间 =
- 总毁花数 =
-
如果先送奶牛 B 再送奶牛 A:
- 总毁花数 =
- 总毁花数 =
要选择更优的顺序,我们需要比较: 2⋅TA⋅DBvs2⋅TB⋅DA
消去常数 2,得到比较条件:
即:当 时,应该先送 A
等价于排序规则:
但为了避免浮点数精度问题,我们使用交叉相乘的比较方式。
算法步骤
- 预处理:将每头奶牛的
乘以 2(因为往返时间)
- 排序:按照比较规则
a.T * b.D < b.T * a.D对奶牛排序- 即:如果
a.T * b.D < b.T * a.D,则 a 应该排在 b 前面
- 即:如果
- 计算答案:
- 维护已花费的总时间
total_time - 按排序后的顺序处理每头奶牛:
- 这头奶牛的等待时间 =
total_time - 毁花数贡献 =
total_time * D_i - 更新
total_time += 2 * T_i
- 这头奶牛的等待时间 =
- 维护已花费的总时间
注:由于
最大为
,
最大为 100,
最大为
,总毁花数可能达到
级别,需要使用
long long。
正确性分析
- 贪心选择性质:任意相邻两头奶牛的最优顺序都满足上述比较规则,因此全局最优解可以通过局部最优选择得到。
- 交换论证:如果存在一个最优解中相邻两头奶牛不满足我们的排序规则,那么交换它们会得到更优或相等的结果,矛盾。
- 边界处理:第一头奶牛等待时间为 0,符合实际情况。
复杂度分析
- 时间复杂度:
,主要消耗在排序
- 空间复杂度:
,存储奶牛信息
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
struct cow{
int time,d;
};
bool cmp(cow& a,cow&b){
return a.d*b.time>b.d*a.time;
}
signed main() {
int n;cin>>n;
vector<cow>v(n);
for(int i=0;i<n;i++){
cin>>v[i].time>>v[i].d;
v[i].time*=2;
}
sort(v.begin(),v.end(),cmp);
int total=0,ans=0;//目前累加的时间,答案
for(int i=0;i<n;i++){
ans+=total*v[i].d;
total+=v[i].time;//当前奶牛等待的时间
}
cout<<ans;
}

京公网安备 11010502036488号