作者:liqiqinai | 来源:互联网 | 2023-10-10 23:54
目录
解题思路演进过程
第一次程序
第二次程序
第三次程序
解题思路演进过程
首先是题目的理解上:有n个商品,n张优惠券,实际上能买的商品个数最多就是n*n,为啥呢,这题默认是买一个商品必须用一张券,而且一个商品每张面值的券只能用一次。也就是,即使有1个6元的商品,当券对这个商品全部用过一次,即使有10元商品和最大面值3的券,也只能够选后者。
第一次我套用了0-1背包的动态规划,但是遗憾的是,由于背包容量(在本题是钱的数量大于10的6次方),即使把真实价格按照从低到高排序,取前1000个,动规本身也会造成超时。
第二次我在计算每件商品实际要付出的价格时,程序是这么写的
int num = 0;
for(int i&#61;0;i&#61;0&&num<1000000;j--){int t &#61; v[i]-c[j];pac[num&#43;&#43;]&#61;t;}
}
此前&#xff0c;v和c都已经从低到高排序了&#xff0c;也就是只读入最小的前100w个&#xff0c;然后使用贪心&#xff0c;只要钱足够就买入。这次没有超时。但是有一个用例是答案错误。
分析可能有两个原因&#xff1a;1.贪心本身就不科学 2.以我刚刚的计算方法&#xff0c;得到的并不是真正最小的前100w个价格。
我尝试计算出所有可能的价格&#xff0c;进行排序&#xff0c;再取前100w个&#xff0c;很遗憾&#xff0c;2个超时&#xff0c;得分甚至更低。
我幡然醒悟&#xff0c;这题是追求最大商品个数&#xff0c;又不是价值&#xff0c;本来就不是动规问题&#xff0c;因此把价值从低到高一件件地往购物车里放就是能够得到最多商品数的策略。
问题就出在如何不超时地得到从低到高的价格排序&#xff0c;且我得到的100w是死的&#xff0c;也许它要100w&#43;1呢&#xff1f;
也就是我的26分程序丢分点可能在于&#xff1a;1.不是严格的小到大价格排序 2.给出的价格排序满足时间复杂度但是剩余的钱还能买
怎么办&#xff1f;只能改成动态的。
友情外链&#xff1a;浙江大学软件学院2020年保研上机模拟练习
我参考上面那位仁兄的思路&#xff0c;主要改进的地方是&#xff0c;使用了优先队列&#xff0c;这样能让最低价格自动上到第一位&#xff0c;并且加入队列的准则是&#xff0c;加入上一个弹出商品次优的价格(如果还有更低的优惠券没用的话&#xff0c;要是没有就不管了)。
第一次程序
#include
#include
#include
#include
#include
#include
#include
#includeusing namespace std;const int maxn &#61; 100010;
const int inf &#61; 1000000&#43;10;//即10^6vector pac;//price after coupon
int dp[inf] &#61; {0};int n,W;
int v[maxn],c[maxn];int main(){scanf("%d %d",&n,&W);for(int i&#61;0;i&#61;pac[i];w--){dp[w] &#61; max(dp[w-pac[i]]&#43;1,dp[w]);}}int maxDp &#61; -1;int maxNum &#61; 0;for(int w &#61; 0;w<&#61;W;w&#43;&#43;){if(dp[w]>maxNum){maxNum &#61; dp[w];maxDp &#61; w;}}printf("%d %d",maxNum,W-maxDp);return 0;
}
第一次结果
第二次程序
#include
#include
#include
#include
#include
#include
#include
#includeusing namespace std;const int maxn &#61; 100010;
const int inf &#61; 1000000&#43;10;//即10^6int pac[1000000];//price after coupon
int dp[inf] &#61; {0};int n,W;
int v[maxn],c[maxn];int main(){scanf("%d %d",&n,&W);for(int i&#61;0;i&#61;0&&num<1000000;j--){int t &#61; v[i]-c[j];pac[num&#43;&#43;]&#61;t;}}sort(pac,pac&#43;num);int left &#61; W;int iNum &#61; 0;for(int i&#61;0;i&#61;pac[i]){left-&#61; pac[i];iNum &#43;&#43;; }if(left<&#61;0)break; }printf("%d %d",iNum,left);return 0;
}
第三次程序
#include
#include
#include
#include
#include
#include
#include
第三次结果