又见背包。hdu 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个学分的组合数。
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
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;
}
原文地址:https://www.cnblogs.com/tom987690183/p/3021213.html