ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

用完全背包解决求极大无关组个数问题

2022-08-02 22:00:49  阅读:107  来源: 互联网

标签:背包 非负 int 系统 个数 无关 货币 include dp


 原题:https://www.acwing.com/problem/content/534/
1 532. 货币系统 2 3 4 在网友的国度中共有 n 种不同面额的货币,第 i 种货币的面额为 a[i],你可以假设每一种货币都有无穷多张。 5 6 为了方便,我们把货币种数为 n、面额数组为 a[1..n] 的货币系统记作 (n,a)。  7 8 在一个完善的货币系统中,每一个非负整数的金额 x 都应该可以被表示出,即对每一个非负整数 x,都存在 n 个非负整数 t[i] 满足 a[i]×t[i] 的和为 x。 9 10 然而,在网友的国度中,货币系统可能是不完善的,即可能存在金额 x 不能被该货币系统表示出。 11 12 例如在货币系统 n=3, a=[2,5,9] 中,金额 1,3 就无法被表示出来。  13 14 两个货币系统 (n,a) 和 (m,b) 是等价的,当且仅当对于任意非负整数 x,它要么均可以被两个货币系统表出,要么不能被其中任何一个表出。  15 16 现在网友们打算简化一下货币系统。 17 18 他们希望找到一个货币系统 (m,b),满足 (m,b) 与原来的货币系统 (n,a) 等价,且 m 尽可能的小。 19 20 他们希望你来协助完成这个艰巨的任务:找到最小的 m。 21 22 输入格式 23 输入文件的第一行包含一个整数 T,表示数据的组数。 24 25 接下来按照如下格式分别给出 T 组数据。  26 27 每组数据的第一行包含一个正整数 n。 28 29 接下来一行包含 n 个由空格隔开的正整数 a[i]。 30 31 输出格式 32 输出文件共有 T 行,对于每组数据,输出一行一个正整数,表示所有与 (n,a) 等价的货币系统 (m,b) 中,最小的 m。 33 34 数据范围 35 1≤n≤100, 36 1≤a[i]≤25000, 37 1≤T≤20 38 输入样例: 39 2 40 4 41 3 19 10 6 42 5 43 11 29 13 19 17 44 输出样例: 45 2 46 5

理解题意,前面大段的是无关内容,最重要的是:

 

 

 很明显了,这不就是线性代数中的求极大无关组个数吗?

即:a数组与b数组之间可以相互表示,b是a的极大无关组

即要在a数组中找到不被数组中任何元素表示出的元素

由于这里系数只能为非负数,所以,一个元素只能被其小于的元素表示

所以我们先排一个序(从小到大),问题就变成了

由 对于a[i]是否能够由a[1],a[2].....a[i-1](无限个)组成,即是否 a[i]=k1*a[1]+k2*a[2]+...ki-1*a[i-1](其中k不全为0);

如果这样写会超时:

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std; const int N = 110; int t; int main() { cin >> t; while (t--) { int a[N], n; cin >> n; for (int i = 1; i <= n; i++) cin >> a[i]; sort(a + 1, a + n + 1); int ans = 0; for (int i = 1; i <= n; i++) //判断这数是否要选 {
        //超时原因在这里,我们可以发现我们浪费了很多已经算过的
        //每次还有再算一遍
bool dp[25010]; memset(dp, false, sizeof(dp)); dp[0] = true; for (int j = 1; j <= i - 1; j++) { for (int k = a[j]; k <= a[i]; k++) { dp[k] |= dp[k - a[j]]; } } if (!dp[a[i]]) ans++; } cout << ans << endl; } return 0; }

其实for(int j=1;j<=i-1;j++)这个for循环可以省略,

写成:

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstring>
 4 using namespace std;
 5 const int N = 110;
 6 int t;
 7 int main()
 8 {
 9     cin >> t;
10     while (t--)
11     {
12         int a[N], n;
13         cin >> n;
14         for (int i = 1; i <= n; i++)
15             cin >> a[i];
16         sort(a + 1, a + n + 1);
17         int ans = 0;
18         bool dp[25010];
19         memset(dp,false,sizeof(dp));
20         dp[0]=true;
21         for (int i = 1; i <= n; i++) 
22         {
23             if (dp[a[i]])
24                 continue;
25             ans++;
26             for (int j = a[i]; j <= a[n]; j++)
27             {
28                 dp[j] |= dp[j - a[i]];
29             }
30         }
31         cout << ans << endl;
32     }
33     return 0;
34 }

 

标签:背包,非负,int,系统,个数,无关,货币,include,dp
来源: https://www.cnblogs.com/cilinmengye/p/16545333.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有