PERKET
## 题目描述
Perket 是一种流行的美食。为了做好 Perket,厨师必须谨慎选择食材,以在保持传统风味的同时尽可能获得最全面的味道。你有 n 种可支配的配料。对于每一种配料,我们知道它们各自的酸度 s 和苦度 b。当我们添加配料时,总的酸度为每一种配料的酸度总乘积;总的苦度为每一种配料的苦度的总和。
众所周知,美食应该做到口感适中,所以我们希望选取配料,以使得酸度和苦度的绝对差最小。
另外,我们必须添加至少一种配料,因为没有任何食物以水为配料的。
## 输入格式
第一行一个整数 n,表示可供选用的食材种类数。
接下来 n 行,每行 2 个整数 si 和 bi,表示第 i 种食材的酸度和苦度。
## 输出格式
一行一个整数,表示可能的总酸度和总苦度的最小绝对差。
### 样例输入 #1
1
3 10
### 样例输出 #1
7
### 样例输入 #2
2
3 8
5 8
### 样例输出 #2
1
### 样例输入 #3
4
1 7
2 6
3 8
4 9
### 样例输出 3
1
【数据】
对于 100% 的数据,有 1 <= n <= 10,且将所有可用食材全部使用产生的总酸度和总苦度小于 1e9 ,酸度和苦度不同时为 1 和 0 。
方法一:dfs (回溯)
#include <bits/stdc++.h> //简单的dfs,就不多解释了
using namespace std;
#define int long long
const int N=12;
int ans=0x3f3f3f3f;
int s[N],b[N];
bool vis[N];
int n,x=1,y=0; //初始化
void dfs(int u)
{
if (u>=n) return ;
for (int i=0;i<n;i++)
{
if (!vis[i])
{
x *=s[i];
y +=b[i];
ans=min(ans,abs(x-y));
vis[i]=1;
dfs(u+1);
vis[i]=0; //恢复现场哦!
x /=s[i];
y -=b[i];
}
}
}
signed main()
{
cin>>n;
for (int i=0;i<n;i++) cin>>s[i]>>b[i];
dfs(0);
cout<<ans;
return 0;
方法二:dfs (不用回溯)
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=12;
int ans=0x3f3f3f3f;
int s[N],b[N];
int n;
void dfs(int u,int x,int y)
{
if (u>=n)
{
if (x==1&&y==0) return ; //判断是否为清水
ans=min(ans,abs(x-y));
return ;
}
dfs(u+1,x*s[u],y+b[u]); //2种情况,选与不选
dfs(u+1,x,y);
}
signed main()
{
cin>>n;
for (int i=0;i<n;i++) cin>>s[i]>>b[i];
dfs(0,1,0);
cout<<ans;
return 0;
}
方法三:位运算 (纯纯暴力)
//位运算,用二进制数表示配料的选择情况,例如有5种配料,二进制数01101则表示选择第1、3、4种配料(从右往左)
//一共有(1<<n-1)-1种选法
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=12;
int ans=0x3f3f3f3f; //初始化
int s[N],b[N];
signed main()
{
int n;
cin>>n;
for (int i=0;i<n;i++) cin>>s[i]>>b[i];
for (int i=1;i<1<<n;i++) //至少选择一种,不能为清水
{
int x=1,y=0;
for (int j=0;j<n;j++)
{
if ((i>>j)&1) //判断第j的位置是否为1,即是否选择
{
x *=s[j];
y +=b[j];
}
}
ans=min(ans,abs(x-y));
}
cout<<ans;
return 0;
}