一:PERKET
题目描述:
Perket 是一种流行的美食。为了做好 Perket,厨师必须谨慎选择食材,以在保持传统风味的同时尽可能获得最全面的味道。你有 nn 种可支配的配料。对于每一种配料,我们知道它们各自的酸度 ss 和苦度 bb。当我们添加配料时,总的酸度为每一种配料的酸度总乘积;总的苦度为每一种配料的苦度的总和。
众所周知,美食应该做到口感适中,所以我们希望选取配料,以使得酸度和苦度的绝对差最小。
另外,我们必须添加至少一种配料,因为没有任何食物以水为配料的。
输入格式
第一行一个整数 nn,表示可供选用的食材种类数。
接下来 nn 行,每行 22 个整数 s_isi 和 b_ibi,表示第 ii 种食材的酸度和苦度。
输出格式
一行一个整数,表示可能的总酸度和总苦度的最小绝对差。
题解:
1:设置函数i是表示目前的配料编号,x为酸度,y为甜度
2:注意,必须大于n才表示全部搜完
3:判断清水的情况
4:分两种情况搜索:1添加 2不添加
5:更新数据
代码:
#include<stdio.h>
int a[100],b[100],n,ans=10000;
void dfs(int i,int x,int y){//i是表示目前的配料编号,x为酸度,y为甜度
if(i>n){
if(x==1&&y==0)return;//判断清水的情况
ans=min(abs(x-y),ans);//更新ans
return;
}
dfs(i+1, x*=a[i], y+=b[i]); //分两种情况搜索:1添加 2不添加
dfs(i+1,x/=a[i],y-=b[i]);
}
int min(int a,int b)
{
if(a<b)return a;
else return b;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d %d",&a[i],&b[i]);
}
dfs(1,1,0);
printf("%d\n",ans);
return 0;
}
二:考前临时抱佛脚
题目描述
这次期末考试,kkksc03 需要考 44 科。因此要开始刷习题集,每科都有一个习题集,分别有 s_1,s_2,s_3,s_4s1,s2,s3,s4 道题目,完成每道题目需要一些时间,可能不等(A_1,A_2,\ldots,A_{s_1}A1,A2,…,As1,B_1,B_2,\ldots,B_{s_2}B1,B2,…,Bs2,C_1,C_2,\ldots,C_{s_3}C1,C2,…,Cs3,D_1,D_2,\ldots,D_{s_4}D1,D2,…,Ds4)。
kkksc03 有一个能力,他的左右两个大脑可以同时计算 22 道不同的题目,但是仅限于同一科。因此,kkksc03 必须一科一科的复习。
由于 kkksc03 还急着去处理洛谷的 bug,因此他希望尽快把事情做完,所以他希望知道能够完成复习的最短时间。
输入格式
本题包含 55 行数据:第 11 行,为四个正整数 s_1,s_2,s_3,s_4s1,s2,s3,s4。
第 22 行,为 A_1,A_2,\ldots,A_{s_1}A1,A2,…,As1 共 s_1s1 个数,表示第一科习题集每道题目所消耗的时间。
第 33 行,为 B_1,B_2,\ldots,B_{s_2}B1,B2,…,Bs2 共 s_2s2 个数。
第 44 行,为 C_1,C_2,\ldots,C_{s_3}C1,C2,…,Cs3 共 s_3s3 个数。
第 55 行,为 D_1,D_2,\ldots,D_{s_4}D1,D2,…,Ds4 共 s_4s4 个数,意思均同上。
题解:
1:利用背包算法
2:如果一个科目中只有一个题目,那么这一科的时间就是这个题目的时间;如果这个科目中有两个题目,那么这一科的时间就是这两个题目时间中较大的那一个。
当这个科目中的题目大于两道时,设这个科目的总时间是t,那么最优时间是t/2,也就是同时做两个科目的时间差为0。
代码:
#include<stdio.h>
int a,b,c,d;//对应s1,s2,s3,s4
int ans;//最后消耗的总时间
int fun(int a){//背包算法
int a1[25],f[2000]={0};
int m=0;//m求出总时间
for(int i=0;i<a;i++) {
scanf("%d",&a1[i]),m+=a1[i];}
if(a==1) return a1[0]; //如果只有一个题目
else if(a==2) return a1[1]>a1[0]?a1[1]:a1[0]; //有两个题目
else {
for(int i=0;i<a;i++){
for(int j=m/2;j>=a1[i];j--){
f[j]=max(f[j],f[j-a1[i]]+a1[i]);
}
}
return max(f[m/2],m-f[m/2]);
}
}
int max(int a,int b)
{
if(a>b) return a;
else return b;
}
int main(){
scanf("%d %d %d %d",&a,&b,&c,&d);
ans=fun(a)+fun(b)+fun(c)+fun(d);
printf("%d",ans);
return 0;
}
知识点:
背包
一、01背包
这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。
用子问题定义状态:即f[i][j]
表示前i件物品恰放入一个容量为j的背包可以获得的最大价值。
则其状态转移方程便是:
f[i][j] = max( f[i-1] [j], f[i-1][j-w[]] + o[i])