【01背包/母函数】HDU2079选课时间(题目已修改,注意读题)【用背包求解方案数】

时间:2021-01-18 18:44:15

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2079

Problem Description 又到了选课的时间了,xhd看着选课表发呆,为了想让下一学期好过点,他想知道学n个学分共有多少组合。你来帮帮他吧。(xhd认为一样学分的课没区别)
 
Input 输入数据的第一行是一个数据T,表示有T组数据。
每组数据的第一行是两个整数n(1 <= n <= 40),k(1 <= k <= 8)。
接着有k行,每行有两个整数a(1 <= a <= 8),b(1 <= b <= 10),表示学分为a的课有b门。
 
Output 对于每组输入数据,输出一个整数,表示学n个学分的组合数。
 
Sample Input
2
2 2
1 2
2 1
40 8
1 1
2 2
3 2
4 2
5 8
6 9
7 6
8 8
 
Sample Output
2
445


背包代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
using namespace std;
int a[10],b[10];
int dp[50];
int main()
{
int t;
cin>>t;
while(t--){
int n,k;
cin>>n>>k;
memset(dp,0,sizeof(dp));
dp[0]=1;
for(int i=1;i<=k;i++)
cin>>a[i]>>b[i];
for(int i=1;i<=k;i++) // 枚举分数不同的课;
for(int m=n;m>=a[i];m--) // 枚举总分数;
for(int j=1;j<=b[i]&&(m>=a[i]*j);j++) // 枚举个数;
dp[m]+=dp[m-a[i]*j];
cout<<dp[n]<<endl;
}
return 0;
}

母函数代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=10005;
struct node{
int a,b;
}stu[10];
int f[maxn];
int tmp[maxn];
int n,m; // n:总学分数,m:不同学分个数
void faction()
{
memset(f,0,sizeof(f));
for(int i=0,t=0;(t<=stu[0].b&&i<=n);(++t,i+=stu[0].a))
f[i]=1;
for(int i=1;i<m;i++){ // 表达式的个数
for(int j=0;j<=n;j++) // 第一个表达式内的每个因子
for(int k=0,t=0;t<=stu[i].b&&k+j<=n;t++,k+=stu[i].a) // 第二个表达式内的每个因子
tmp[j+k]+=f[j];
for(int j=0;j<=n;j++){
f[j]=tmp[j];
tmp[j]=0;
}
}
}
bool cmp(node a,node b)
{
return a.a<b.a;
}
int main()
{
int t;
cin.sync_with_stdio(false);
cin>>t;
while(t--){
cin>>n>>m;
for(int i=0;i<m;i++)
cin>>stu[i].a>>stu[i].b;
sort(stu,stu+m,cmp);
faction();
cout<<f[n]<<endl;
}
return 0;
}