找单词
假设有x1个字母A, x2个字母B,… x26个字母Z,同时假设字母A的价值为1,字母B的价值为2,… 字母Z的价值为26。那么,对于给定的字母,可以找到多少价值<=50的单词呢?单词的价值就是组成一个单词的所有字母的价值之和,比如,单词ACM的价值是1+3+14=18,单词HDU的价值是8+4+21=33。(组成的单词与排列顺序无关,比如ACM与CMA认为是同一个单词)。
输入格式:
输入首先是一个整数N,代表测试实例的个数。
然后包括N行数据,每行包括26个<=20的整数x1,x2,…x26.
输出格式:
对于每个测试实例,请输出能找到的总价值<=50的单词数,每个实例的输出占一行。
输入样例:
2
1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
9 2 6 2 10 2 2 5 6 1 0 2 7 0 2 2 7 5 10 6 10 2 10 6 1 9
输出样例:
在这里给出相应的输出。例如:
7
379297
分析:
- 题目大意
说我们有A~Z 26个字母每一个字母有若干个,我们可以取出来任意多个拼成一个单词,但是单词的和不能超过50,单词的不同与字母的位置无关之和每一个字母的个数有关。 - 思路
这其实是一个背包问题是一个多重背包,我们可以想象每一个字母是一类物品我们可以从这类物品中选择若干个物品,但是物品的总价值不能超过50,这就转换成背包问题求方案数,转换一个变成我们的模板题 - 状态转移方程
我们可以设f[i][j],i表示从先几个子母中选择类j表示但前允许的最大价值是多少。设k是我们当前的物品选择了多少个.
当j-ki>=0时f[i][j]+=f[i-1][j-ki];
#include<bits/stdc++.h>
using namespace std;
const int N = 205;
int a[N], c[N];
int n, m;
int b[N];
int f[N][N];
int main() {
int t;
cin >> t;
while (t--) {
memset(f,0,sizeof f);
for (int i = 1; i <= 26; i++)scanf("%d", &a[i]);
f[0][0]=1;
for (int i = 1; i <= 26; i++) {
for (int j = 0; j <= 50; j++) {
for (int k = 0; k <= a[i] && k * i <= j; k++) {
f[i][j] += f[i - 1][j - k * i];
}
}
}
int ans=0;
for(int i=0;i<=50;i++)
ans+=f[26][i];
cout << ans-1<<endl;//减一为了减去f[0][0]
}
}