原题链接https://acm.dingbacode.com/showproblem.php?pid=1300题意:
一个公司要买珍珠,总共有100个品质的珍珠,对于每个品质的珍珠,如果要购买必须额外支付10颗珍珠的价钱。有些方案可以花更少的钱买更高的品质的珍珠,但是不能买更差的珍珠,求每份清单最少花的钱。
反思:
赛时的错误思路:
个人赛的时候没有写出来,没有想到dp,甚至赛后查题解的时候也不能理解为什么要用dp。比赛的时候的思路大概是下面这样 如果可以买得起订单上更好一级品质的珍珠,就把当前品质的珍珠数量加到上面那一级去,这样重复然后逐级往上。
//这个代码是错哒!
for(int i=0;i<n-1;++i)
{
if((a[i]+10)*p[i]>=p[i+1]*a[i])
{
a[i+1]+=a[i];
a[i]=0;
}
}
for(int i=0;i<n;++i)
if(a[i]!=0)
sum+=((10+a[i])*p[i]);
赛时觉得没问题,以为是细节错了。结果赛后一看,怎么是dp......晚上回去想了想,自己原来的思路确实有问题。之前那样的方式只比较了钱的多少没有具体记录下来,钱少了就往前买更好一级品质的珍珠,可是没有算买了更好的珍珠而省下来的钱,这省下来的钱可能在之后整体买更高一级的珍珠上可以用到。
查了题解,大家给这题取的标题是容易dp,或者..”看了题目,很容易想到用到dp“之类的话
好叭 还是做题少了~
感觉自己还是太容易陷进自己的思维就出不来了,下次记得wa的时候想想自己的方法有没有存在漏洞。
代码:
#include<iostream>
#include<algorithm>
const int N=105;
int a[N],p[N],dp[N],cnt[N];
int main()
{
using namespace std;
int T,c;
cin>>T;
while(T--)
{
cin>>c;
for(int i=1;i<=c;++i)
{
cin>>a[i]>>p[i];
cnt[i]=cnt[i-1]+a[i];//cnt数组记录前i种珍珠的数量总和
dp[i]=dp[i-1]+(a[i]+10)*p[i];//先不考虑最优的情况
}
for(int i=2;i<=c;++i)//dp[i]表示前i种最少花费的钱数
for(int j=0;j<i;++j)
dp[i]=min(dp[i],dp[j]+(cnt[i]-cnt[j]+10)*p[i]);//表示第j种到第i种都在品质i上购买
cout<<dp[c]<<endl;
}
}
疑问:
上面是参考别人代码的,但是看了仍存在几个疑问。
1.为什么在优化方案时一定要取连续种类的珍珠?
因为比如在A,B,C三个依次递增的品质的珍珠里购买,如果B按自己的价格购买,那么以B的价格来买A肯定比以C的价格来买B要便宜。而题目里说是想通过购买比实际需要的更高质量的珍珠来省钱 而不是一定要追求更好品质的珍珠,所以这里一定是连续的区间。
2.为什么j的循环要从j=0开始?珍珠的标号在这里不是从1开始吗?
因为要考虑所有情况,有可能前面一个珍珠都不取,全部取最高品质的珍珠。