hdu2079选课时间(动态规划&&母函数)

来源:互联网 发布:js验证用户名是否存在 编辑:程序博客网 时间:2024/05/22 05:22

选课时间(题目已修改,注意读题)

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3513    Accepted Submission(s): 2772


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
22 21 22 140 81 12 23 24 25 86 97 68 8
 

Sample Output
2445
题目大意:给出要修够的学分及可以选修的课,问有多少种方案可以修够这些学分?
解题思路:本题的解法大致有两种,一个是动态规划,一个是母函数,感觉组合问题大多都能用动态规划和母函数解决。
其中动态规划的解法为:
已知 需修够学分 N,各学分s[i],及其对应的 课的数num[i].
若用j表示需修够学分,则修够学分为j的方案数就是已经找到的方案数dp[j]和当已修l*s[i]学分时,要修够j学分的方案数即dp[j-l*s[i]]。则可得动态转移方程为:
dp[j] = dp[j] + dp[j-l*s[i]] (j = n,n-1,...1; l = 1,2,3,...num[i]).
ac代码:
#include<stdio.h>#include<string.h>int dp[45];int main(){    int t;    int n,k,i,j,l;    int s[10],num[10];    scanf("%d",&t);    while(t- -)    {        scanf("%d%d",&n,&k);        for(i=0;i<k;i++)         scanf("%d%d",&s[i],&num[i]);        memset(dp,0,sizeof(dp));        dp[0]=1;        for(i=0;i<k;i++)        {            for(j=n;j>=s[i];j--)            {                for(l=1;(j-l*s[i])>=0&&l<=num[i];l++)                {                    dp[j]=dp[j]+dp[j-l*s[i]];                }            }        }    printf("%d\n",dp[n]);    }return 0;}
母函数的解法为:
已知母函数的通式为 G(x) = 1 + a[1]x + a[2]x^2 + a[3]x^3 +.........+ a[n]x^n
其中,每一项x的系数a[i]就可以表示幂数i的划分的方案数。
应用到本题中可知:
学分为1的可以表示的学分为:1 + x + x^2 + x^3 + x^4 +....
学分为2的可以表示的学分为:1 + x^2 + x^4 + x^6 +........
学分为3的可以表示的学分为:1 + x^3 + x^6 + x^9+.........
以此类推
用所给的各学分所能表示的多项式相乘,化简后得到a[n]x^n,a[n]就是要修够学分n的方案数。
代码如下;
#include<stdio.h>#include<string.h>int c1[1010],c2[1010];int main(){int t,n,k;int i,j,l,num;int a[10],b[10];scanf("%d",&t);while(t--){scanf("%d%d",&n,&k);num=0;for(i=0;i<k;i++){ scanf("%d%d",&a[i],&b[i]);}memset(c2,0,sizeof(c2));    for(i=1;i<=k;i++)    {    for(j=0;j<=n;j++)    {    for(l=0;l+j<=n;l+=a[i])    {    c2[l+j]+=c1[j];}}for(j=0;j<=n;j++){c1[j]=c2[j],c2[j]=0;}}printf("%d\n",c1[n]);}return 0;}




0 0
原创粉丝点击