现在我们有 n 个物品,每个物品的花费为:ai,求把所有的物品购买下来所需要的最小硬币个数是多少?在我们合理规划硬币的面值 bi 的情况下。
思路
挺不错的一题。。。虽然没有做出来 ╮(╯▽╰)╭
当时在考虑状态转移的时候,一直找不到 到底使用哪个状态进行转移的,
其实这题的状态转移是通过倍数关系去实现的,
我们设状态转移方程为:dp [i] 表示面值序列 b 中的最后一个最大的面值为 i 的时候买下 n 个物品的需要的最少硬币数量。
我们考虑 i 个的一个倍数 k, 设 i * j = k, 我们考虑当状态从 dp [i] 转 -> 移到 dp [k] 的时候,我们我们买物品的时候的发生的变化,
当最大面值为 i 的时候,我们买一个 k 花费的物品需要 j 个硬币,
而当最大面值为 k 的时候,我们买一个 k 花费的物品需要的 i 个硬币,
因此对于买一个 k 物品的价值相较于之前,可以可以 少使用 j-1 个硬币,
所以当 dp [i] 向 dp [k] 转移的时候的状态方程为:
d
p
[
k
]
=
m
i
n
(
d
p
[
k
]
,
d
p
[
i
]
−
总
共
节
约
的
硬
币
数
量
)
dp [k] = min (dp [k], dp [i] - 总共节约的硬币数量)
dp[k]=min(dp[k],dp[i]−总共节约的硬币数量)
具体请看代码把。
代码
#include<bits/stdc++.h>
using namespace std;#definedbdouble#definelllonglong#definescscanf#defineprprintf#definefifirst#definesesecond#definepbpush_back#definem_pmake_pair#definePirpair<int,int>#defineinf0x3f3f3f3f#defineINF0x3f3f3f3f3f3f3f3f/*==========ACMer===========*/constint N =5e4+10;int a[N];int dp[N];intmain(){int n;sc("%d",&n);int sum =0, mx =0;for(int i =1; i <= n; i ++){sc("%d",&a[i]);
sum += a[i];
mx =max(mx, a[i]);}memset(dp, inf,sizeof dp);
dp[1]= sum;int ans = dp[1];for(int i =1; i <= mx; i ++){
ans =min(ans, dp[i]);for(int j =2; j * i <= mx; j ++){int num =0;for(int k =1; k <= n; k ++)
num += a[k]/(i * j);
dp[i * j]=min(dp[i * j], dp[i]- num *(j -1));}}pr("%d\n", ans);return0;}