P2036 [COCI 2008/2009 #2] PERKET-dfs
题目描述
Perket 是一种流行的美食。为了做好 Perket,厨师必须谨慎选择食材,以在保持传统风味的同时尽可能获得最全面的味道。你有 n 种可支配的配料。对于每一种配料,我们知道它们各自的酸度 s 和苦度 b。当我们添加配料时,总的酸度为每一种配料的酸度总乘积;总的苦度为每一种配料的苦度的总和。
众所周知,美食应该做到口感适中,所以我们希望选取配料,以使得酸度和苦度的绝对差最小。
另外,我们必须添加至少一种配料,因为没有任何食物以水为配料的。
输入格式
第一行一个整数 n,表示可供选用的食材种类数。
接下来 n 行,每行 2 个整数 s**i 和 b**i,表示第 i 种食材的酸度和苦度。
输出格式
一行一个整数,表示可能的总酸度和总苦度的最小绝对差。
输入输出样例
输入
1
3 10
输出
7
输入
2
3 8
5 8
输出
1
输入
4
1 7
2 6
3 8
4 9
输出
1
说明/提示
数据规模与约定
对于 100% 的数据,有 1≤n≤10,且将所有可用食材全部使用产生的总酸度和总苦度小于 1×109,酸度和苦度不同时为 1 和 0。
代码详细注释说明:
-
定义常量和变量:
const int N = 20;
:定义最大食材种类数N
,题目中限制n <= 10
,所以这里给定一个较大的常量20
以保证能够容纳输入。int acid[N], bitter[N];
:分别存储每种食材的酸度和苦度。int st[N];
:用于标记每种食材是否被选中,st[i] == 1
表示选中第i
种食材,st[i] == 0
表示未选,st[i] == 2
作为一种回溯标记(用于后续没有进一步操作时)。int res = INT_MAX;
:初始化res
为一个很大的数,之后用来记录最小的酸度与苦度差值。
-
dfs
函数:-
递归的深度优先搜索函数,
dfs(x)
用来遍历从食材x
开始的所有可能选择(选或不选)。 -
如果递归到达了
x > n
,即所有食材都已经考虑过,则开始计算当前选择的酸度和苦度。
- 酸度:所有选中的食材的酸度的乘积。
- 苦度:所有选中的食材的苦度的和。
-
如果至少选择了一个食材(
flag == true
),则更新最小的误差res
,即酸度和苦度的绝对差。
-
-
回溯的过程:
- 在每一层递归中,首先尝试不选当前食材(
st[x] = 0
),然后递归处理剩下的食材。 - 接着再尝试选当前食材(
st[x] = 1
),递归处理剩下的食材。 - 这样通过递归,遍历所有可能的选择组合。
- 在每一层递归中,首先尝试不选当前食材(
-
main
函数:- 读取食材的数量
n
和每种食材的酸度、苦度。 - 调用
dfs(1)
开始从第 1 种食材开始递归,进行所有可能的选择。 - 最后输出
res
,即最小的酸度与苦度的差值。
- 读取食材的数量
#include <bits/stdc++.h>
using namespace std;
const int N = 20; // 定义最大食材种类数
int n; // 食材的数量
int acid[N], bitter[N]; // 存储每种食材的酸度和苦度
int st[N]; // 标记每种食材是否被选中(0表示未选,1表示已选)
int res = INT_MAX; // 存储最小的酸度和苦度的绝对差
// 递归深度优先搜索函数
void dfs(int x) {
// 当递归到所有食材都被考虑过时
if (x > n) {
int sum1 = 1; // 初始化酸度之积
int sum2 = 0; // 初始化苦度之和
bool flag = false; // 用于标记是否选择了至少一种食材
// 遍历所有食材,计算选择的食材的酸度和苦度
for (int i = 1; i <= n; i++) {
if (st[i] == 1) { // 如果第 i 种食材被选中
flag = true; // 标记为选中了至少一种食材
sum1 *= acid[i]; // 更新酸度之积
sum2 += bitter[i]; // 更新苦度之和
}
}
// 如果至少选择了一种食材,计算并更新最小的酸度和苦度的差值
if (flag) {
res = min(res, abs(sum1 - sum2)); // 计算并更新最小差值
}
return; // 递归终止
}
// 不选择第 x 种食材
st[x] = 0; // 标记第 x 种食材为未选择
dfs(x + 1); // 递归处理下一个食材
// 选择第 x 种食材
st[x] = 1; // 标记第 x 种食材为已选择
dfs(x + 1); // 递归处理下一个食材
// 回溯,恢复第 x 种食材的选择状态
st[x] = 2; // 2 表示不需要标记,实际上用于标记不做进一步操作
}
int main() {
cin >> n; // 输入食材的数量
// 输入每种食材的酸度和苦度
for (int i = 1; i <= n; i++) {
cin >> acid[i] >> bitter[i]; // 输入酸度和苦度
}
// 从第 1 种食材开始递归,初始化递归
dfs(1);
// 输出计算得到的最小的酸度和苦度的绝对差
cout << res << endl;
return 0;
}