讨厌鬼进货
思路
这道题乍一看有三种进货方式,感觉挺复杂?别急,咱们理一下:
- 每种货物可以从供应商 1 买,花 a[i]
- 也可以从供应商 2 买,花 b[i]
- 还有个网购平台,花 c 元一次性买齐所有 n 种
那问题来了——如果不用网购平台,怎么买最便宜?是不是每种货物都挑两个供应商里便宜的那个就行了?对,就是 min(a[i], b[i]) 逐个取最小值,然后加起来。
那网购平台呢?它是一口价 c 元买齐全部,不能拆分。所以要么全用网购,要么完全不用网购、每种货物自己从供应商里挑。
> 等等,能不能"部分从供应商买 + 网购也买"混着来?
可以混着来,但你想想:网购已经花了 c 元把所有东西都买了,再从供应商买就是浪费钱。所以最优方案一定是二选一——要么纯供应商方案,要么纯网购方案。
最终答案就是两种方案取最小值:。
具体步骤
- 读入 n、c 和两个数组 a、b
- 遍历每种货物,累加 min(a[i], b[i])
- 拿累加结果和 c 比较,输出较小的那个
代码
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int n, c;
cin >> n >> c;
int a[n], b[n];
for (int i = 0; i < n; i++) cin >> a[i];
for (int i = 0; i < n; i++) cin >> b[i];
long long sum = 0;
for (int i = 0; i < n; i++) {
sum += min(a[i], b[i]);
}
cout << min(sum, (long long)c) << endl;
return 0;
}
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int c = sc.nextInt();
int[] a = new int[n];
int[] b = new int[n];
for (int i = 0; i < n; i++) a[i] = sc.nextInt();
for (int i = 0; i < n; i++) b[i] = sc.nextInt();
long sum = 0;
for (int i = 0; i < n; i++) {
sum += Math.min(a[i], b[i]);
}
System.out.println(Math.min(sum, c));
}
}
n, c = map(int, input().split())
a = list(map(int, input().split()))
b = list(map(int, input().split()))
s = sum(min(x, y) for x, y in zip(a, b))
print(min(s, c))
const readline = require('readline');
const rl = readline.createInterface({ input: process.stdin });
const lines = [];
rl.on('line', line => lines.push(line));
rl.on('close', () => {
const [n, c] = lines[0].split(' ').map(Number);
const a = lines[1].split(' ').map(Number);
const b = lines[2].split(' ').map(Number);
let sum = 0;
for (let i = 0; i < n; i++) {
sum += Math.min(a[i], b[i]);
}
console.log(Math.min(sum, c));
});
复杂度分析
- 时间复杂度:
,遍历一次数组
- 空间复杂度:
,存储两个数组
总结
这题本质上就是个贪心:先算出供应商方案的最优成本(每种货物哪家便宜买哪家),再和网购一口价比一比,取小的就完了。关键是想清楚"网购和供应商混合购买"不会比两个纯方案更优,因为网购没法拆分,用了就是全买。典型的"想清楚就三行核心代码"的贪心入门题。



京公网安备 11010502036488号