1.自然数的拆分求方案数
时间限制:1秒 内存限制:128M
题目描述
给定一个自然数N,要求把N拆分成若干个正整数相加的形式,参与加法运算的数可以重复。注意:拆分方案不考虑顺序;至少拆分成2个数的和。 1≤N≤4000
求拆分的方案数 mod2147483648 的结果。
输入描述
一个自然数N。
输出描述
输入一个整数,表示结果。
样例
输入
7
输出
14
提示
1+1+1+1+1+1+1
1+1+1+1+1+2
1+1+1+1+3
1+1+1+2+2
1+1+1+4
1+1+2+3
1+1+5
1+2+2+2
1+2+4
1+3+3
1+6
2+2+3
2+5
3+4(共14行)
思路详解:
此题可想成完全背包问题,只需注意dp数组类型,不要为int整型,会爆(因为2147483648,INT_max)。
AC代码:
#include<iostream>
using namespace std;
const int m=2147483648ll;
int n;
long long dp[4005];
int main(){
cin>>n;
dp[0]=1;
for (int i=1;i<n;i++){ //物品
for (int j=i;j<=n;j++){ //容量
dp[j]+=dp[j-i];
dp[j]=dp[j]%m;
}
}
cout<<dp[n];
return 0;
}
2.自然数的拆分
时间限制:1秒 内存限制:128M
题目描述
任何一个大于1的自然数n,
总可以拆分成若干个小于n的自然数之和。
当n=7共14种拆分方法:
7=1+1+1+1+1+1+1
7=1+1+1+1+1+2
7=1+1+1+1+3
7=1+1+1+2+2
7=1+1+1+4
7=1+1+2+3
7=1+1+5
7=1+2+2+2
7=1+2+4
7=1+3+3
7=1+6
7=2+2+3
7=2+5
7=3+4
total=14
输入描述
输入n。
输出描述
按字典序输出具体的方案。
样例
输入
7
输出
1+1+1+1+1+1+1 1+1+1+1+1+2 1+1+1+1+3 1+1+1+2+2 1+1+1+4 1+1+2+3 1+1+5 1+2+2+2 1+2+4 1+3+3 1+6 2+2+3 2+5 3+4
思路详解:
因为数据量小,所以用DFS不会爆,用temp存储,k为下标指示器,为减少时间,防止时间爆掉,可以从上一个数开始找。
AC代码:
#include<iostream>
using namespace std;
int n,temp[15]={1};
void dfs(int sum,int k){
if (sum==0){
cout<<temp[1];
for (int i=2;i<k;i++){
cout<<"+"<<temp[i];
}
cout<<endl;
}
for (int i=temp[k-1];i<n;i++){
if (sum>=i){
temp[k]=i;
dfs(sum-i,k+1);
temp[k]=0;
}
}
}
int main(){
cin>>n;
dfs(n,1);
return 0;
}
3.货币系统
题目描述
在网友的国度中共有 n 种不同面额的货币,第 i 种货币的面额为 a[i],你可以 假设每一种货币都有无穷多张。为了方便,我们把货币种数为 n、面额数组为 a[1..n] 的货币系统记作 (n,a)。
在一个完善的货币系统中,每一个非负整数的金额 x 都应该可以被表示出,即对 每一个非负整数 x,都存在 n 个非负整数 t[i] 满足 a[i]× t[i] 的和为 x。然而, 在网友的国度中,货币系统可能是不完善的,即可能存在金额 x 不能被该货币系统表 示出。例如在货币系统 n=3, a=[2,5,9] 中,金额 1,3 就无法被表示出来。
两个货币系统 (n,a) 和 (m,b) 是等价的,当且仅当对于任意非负整数 x,它要 么均可以被两个货币系统表出,要么不能被其中任何一个表出。
现在网友们打算简化一下货币系统。他们希望找到一个货币系统 (m,b),满足 (m,b) 与原来的货币系统 (n,a) 等价,且 m 尽可能的小。他们希望你来协助完成这 个艰巨的任务:找到最小的 m。
输入描述
输入文件名为 money.in。
输入文件的第一行包含一个整数 T,表示数据的组数。接下来按照如下格式分别给 出 T 组数据。
每组数据的第一行包含一个正整数 n。接下来一行包含 n 个由空格隔开的正整数 a[i]。
输出描述
输出文件名为 money.out。
输出文件共有 T 行,对于每组数据,输出一行一个正整数,表示所有与 (n,a) 等 价的货币系统 (m,b) 中,最小的 m。
样例
输入
2 4 3 19 10 6 5 11 29 13 19 17
输出
2 5
提示
在第一组数据中,货币系统(2,[3,10])和给出的货币系统(n,a)等价,并可以验证不存在m<2的等价的货币系统,依次答案为2.
在第二组数据中,可以验证不存在m<n,的等价的货币系统,因此答案为5.
对于 100% 的数据,满足 1 ≤ T ≤ 20,1≤n≤ 100,1≤ a[i] ≤ 25000。
思路详解:
多次输入记得初始化,使用动态规划判断哪些面额的货币是必要的。对货币面额进行排序,然后依次判断每个面额是否能被前面的面额组合表示出来。如果不能,则该面额是必要的。
AC代码:
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int t,n,dp[25005],a[105];
int cnt=0;
int main(){
cin>>t;
while (t--){
cin>>n;
cnt=0;
memset(dp,0,sizeof(dp));
for (int i=1;i<=n;i++){
cin>>a[i];
}
sort(a+1,a+n+1);
dp[0]=1;
for (int i=1;i<=n;i++){ //物品
for (int j=a[i];j<=a[n];j++){ //容量
dp[j]+=dp[j-a[i]];
}
}
for (int i=1;i<=n;i++){
if (dp[a[i]]==1){
cnt++;
}
}
cout<<cnt<<endl;
}
return 0;
}