其他分享
首页 > 其他分享> > 用完全背包解决求极大无关组个数问题

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

作者:互联网

 原题: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