随笔 - 766 文章 - 1 评论 - 107
八.背包问题方案总数
对于一个给定了背包容量、物品费用、物品间相互关系(分组、依赖等)的背包问题,除了再给定每个物品的价值后求可得到的最大价值外,还可以得到装满背包或将背包装至某一指定容量的方案总数。
对于这类改变问法的问题,一般只需将状态转移方程中的max改成sum即可。例如若每件物品均是01背包中的物品,转移方程即为f[i][v]=sum{f[i-1][v],f[i-1][v-w[i]]+c[i]},初始条件f[0][0]=1。
事实上,这样做可行的原因在于状态转移方程已经考察了所有可能的背包组成方案。
货币系统
【问题描述】
给你一个n种面值的货币系统,求组成面值为m的货币有多少种方案。样例:设n=3,m=10,要求输入和输出的格式如下:
【样例输入】money.in
3 10 //3种面值组成面值为10的方案
1 //面值1
2 //面值2
5 //面值5
【样例输出】money.out
10 //有10种方案
算法 设f[j]表示面值为j的最大方案数, 如果f[j-k*a[i]]!=0则f[j]=f[j]+f[j-k*a[i]],当1<=i<=n,m>=j>= a[i],1<=k<=j / a[i]。 #include<cstdio> int m, n; int a[1001]; long long f[10001]; int main() { scanf("%d%d",&n,&m); for (int i = 1; i <= n; i++) scanf("%d",&a[i]); f[0] = 1; for (int i = 1; i <= n; i++) for (int j = m; j >= a[i]; j--) for (int k = 1; k <= j / a[i]; k++) f[j] += f[j-k*a[i]]; printf("%lld",f[m]); return 0; }
【算法分析2】 设f[j]表示面值为j的总方案数,如果f[j-a[i]]!=0则f[j]=f[j]+f[j-a[i]],1<=i<=n,a[i]<=j<=m。 【参考程序2】 #include<cstdio> using namespace std; int n, m; int a[101]; long long f[10001]; int main(){ scanf("%d%d",&n,&m); for (int i = 1; i <= n; i++) scanf("%d",&a[i]); f[0] = 1; for (int i = 1; i <= n; i++) for (int j = a[i]; j <= m; j++) f[j] += f[j-a[i]]; printf("%lld",f[m]); return 0; }
题目背景
uim神犇拿到了uoi的ra(镭牌)后,立刻拉着基友小A到了一家……餐馆,很低端的那种。
uim指着墙上的价目表(太低级了没有菜单),说:“随便点”。
题目描述
不过uim由于买了一些辅(e)辅(ro)书,口袋里只剩M元(M<=10000)。
餐馆虽低端,但是菜品种类不少,有N种(N<=100),第i种卖ai元(ai<=1000)。由于是很低端的餐馆,所以每种菜只有一份。
小A奉行“不把钱吃光不罢休”,所以他点单一定刚好吧uim身上所有钱花完。他想知道有多少种点菜方法。
由于小A肚子太饿,所以最多只能等待1秒。
输入输出格式
输入格式:
第一行是两个数字,表示N和M。
第二行起N个正数ai(可以有相同的数字,每个数字均在1000以内)。
输出格式:
一个正整数,表示点菜方案数,保证答案的范围在int之内。
输入输出样例
输入样例#1:
复制
4 4 1 1 2 2
输出样例#1: 复制
3
#include<iostream>
using namespace std;
int dp[10002];
int c[102];
int main()
{
int n,v;
cin>>n>>v;
for(int i=1;i<=n;i++) cin>>c[i];
dp[0]=1;
for(int i=1;i<=n;i++)
{
for(int j=v;j>=c[i];j--)
dp[j]+=dp[j-c[i]];
}
cout<<dp[v]<<endl;
}
原文地址:https://www.cnblogs.com/damaoranran/p/9053932.html