选课时间(题目已修改,注意读题)
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门
每组数据的第一行是两个整数n(1 <= n <= 40),k(1 <= k <= 8)。
接着有k行,每行有两个整数a(1 <= a <= 8),b(1 <= b <= 10),表示学分为a的课有b门
Output
对于每组输入数据,输出一个整数,表示学n个学分的组合数。
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
2 2
1 2
2 1
40 8
1 1
2 2
3 2
4 2
5 8
6 9
7 6
8 8
2
445
445
思路: dp[i][j]=dp[i-1][j]+dp[i-t][j-a[i]*t];
代表 前i中课获得j个学分的种类数 = 第i种课程没有获得 + 第i种课程获得了学分,并且个数t个。
个数的装入需要一些技巧,为了防止对第i种课程的重复使用,要合理的投放。 分组背包的思想。(其实也不能这么说,关键是要自己画图,就能得到了)
对于n->a[i] 向n投放 1个或2个或3个...t个的第j种课程。
代码:
#include<stdio.h> int main() { int f[41],a[9],b[9]; int i,j,k,n,m,t; while(scanf("%d",&n)>0) { while(n--) { scanf("%d%d",&m,&k); for(i=1;i<=k;i++) scanf("%d%d",&a[i],&b[i]); for(i=1;i<=m;i++) f[i]=0; f[0]=1; for(i=1;i<=k;i++) for(j=m;j>=a[i];j--) for(t=1;t<=b[i]&&j>=a[i]*t;t++) //关键。 if(f[j-a[i]*t]!=0) f[j]=f[j]+f[j-a[i]*t]; printf("%d\n",f[m]); } } return 0; }