洛谷P5020(Noip2018货币系统)

本题就是一个贪心+完全背包,很容易想到如果想要用化简会被其他货币凑出的货币,那么就必须从小到大凑(因为大的一定凑不出小的,而小的有可能凑出大的)。所以由此如何判断呢?就写一个完全背包判断(而且不用每新的货币就重新计算,可以从前往后依次计算(减小时间复杂度))。这样判断后若无法凑出就ans++。(好了上代码!)

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cmath>
 4 #include<string>
 5 #include<cstring>
 6 using namespace std;
 7 int T;
 8 int num[109];
 9 int n,ans;//ans记录答案
10 bool dp[25009];//记录在某货币之前的所有货币可能凑出的值(false为不能,true为能)
11 int maxn;//记录整个货币系统中最大的面值
12 bool judge(int m)//判断num[m]是否已经凑出并计算加上这个面值之后可以凑出的值
13 {
14     if(dp[num[m]]==true)return true;//已经凑出了就返回true
15     dp[num[m]]=true;//那么就需要将其标记为true
16     for(int j=num[m];j<=maxn;j++)//完全背包模板但是已经知道了这个数是多少就不用去枚举了
17     {
18         if(dp[j-num[m]]==true)dp[j]=true;
19     }
20     return false;//直接返回false
21 }
22 void shaishu()
23 {
24     for(int i=1;i<=n;i++)
25     {
26         if(judge(i)==true)continue;//如果是可以被凑出ans就不用增加
27         else ans++;
28     }
29 }
30 int main()
31 {
32     cin>>T;
33     while(T--)
34     {
35         memset(num,0,sizeof(num));
36         memset(dp,false,sizeof(dp));//一定要清空dp不然上几组数据的值都会残留在其中使答案不对
37         ans=0;//同时将ans归零
38         cin>>n;
39         for(int i=1;i<=n;i++)cin>>num[i],maxn=max(maxn,num[i]);//在读入的同时计算出最大的面值
40         sort(num+1,num+n+1);//排序将小面值放在前面
41         shaishu();//开始筛选
42         cout<<ans<<endl;//最后输出结果
43     }
44 }

原文地址:https://www.cnblogs.com/1129-tangqiyuan/p/11187374.html