[COCI 2008/2009 #2] PERKET

GitHub跳转原题关系图返回列表

枚举所有非空食材组合,计算酸度乘积和苦度总和,取二者差值的最小值。

OJ: luogu

题目 ID: P2036

难度:入门

标签:枚举组合python

日期: 2026-07-15 21:50

题意

n 种食材,每种有酸度 s 和苦度 b。选择至少一种食材后:

  • 总酸度是所有 s 的乘积;
  • 总苦度是所有 b 的和。

要求最小化 abs(总酸度 - 总苦度)

思路

n <= 10,可以枚举所有非空组合。

对每个组合:

  1. sour1 开始,乘上每个食材的酸度;
  2. bitter0 开始,加上每个食材的苦度;
  3. abs(sour - bitter) 更新答案。

Python 知识

  • combinations(ingredients, size) 枚举选 size 个食材的所有组合。
  • answer = None 可以表示“还没有任何候选答案”,避免随便写一个很大的初值。
  • 元组解包 for s, b in chosen 让代码直接对应酸度和苦度。

参考笔记:

  • /home/rainboy/mycode/hugo-blog/content/program_language/python/brute_force_validation.md
  • /home/rainboy/mycode/hugo-blog/content/program_language/python/math_tools.md

代码

python
from itertools import combinations

n = int(input())
ingredients = [tuple(map(int, input().split())) for _ in range(n)]

answer = None

for size in range(1, n + 1):
    for chosen in combinations(ingredients, size):
        sour = 1
        bitter = 0
        for s, b in chosen:
            sour *= s
            bitter += b
        difference = abs(sour - bitter)
        if answer is None or difference < answer:
            answer = difference

print(answer)
cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-07-27 00:00
 * update_at: 2026-07-27 00:00
 */
#include <bits/stdc++.h>
using namespace std;

int n, ans = 2e9;
int s[15], b[15];

void dfs(int dep, int sour, int bitter, bool used) {
    if (dep == n) {
        if (used && abs(sour - bitter) < ans)
            ans = abs(sour - bitter);
        return;
    }
    dfs(dep + 1, sour, bitter, used);           // 不放当前食材
    dfs(dep + 1, sour * s[dep], bitter + b[dep], true); // 放
}

int main() {
    cin >> n;
    for (int i = 0; i < n; i++) cin >> s[i] >> b[i];
    dfs(0, 1, 0, false);
    cout << ans << endl;
    return 0;
}

复杂度

一共有 2n12^n-1 个非空组合,每个组合最多处理 n 个食材,时间复杂度为 O(n2n)O(n2^n),空间复杂度为 O(n)O(n)

总结

数据范围很小,最稳妥的做法就是直接枚举所有非空选择,不要过度设计。