HDU 2079 dp解法

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

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

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

题意  中文题,不说了

题解   这题我们设一个dp[ i ]数组( i 表示学分数,dp[i]就是组成i学分的组合数),枚举每个课程,求出包括前面课程所能组成的学分,对数组进行更新

0.0......说的自己都不明白---_---!!!。

AC代码

 1 #include <stdio.h>
 2 #include <math.h>
 3 #include <string.h>
 4 #include <stdlib.h>
 5 #include <iostream>
 6 #include <sstream>
 7 #include <algorithm>
 8 #include <string>
 9 #include <queue>
10 #include <vector>
11 #define maxn 100005
12 #define maxm 50000
13 using namespace std;
14 typedef long long ll;
15 int dp[50];
16 struct  course
17 {
18   int s;
19   int n;
20 }f[10];
21 int main(int argc, char const *argv[])
22 {
23   int t;
24   cin>>t;
25   while(t--)
26   {
27     int n,m;
28     cin>>n>>m;
29     memset(dp,0,sizeof(dp));
30     for(int i=1;i<=m;i++)
31     {
32       cin>>f[i].s>>f[i].n;
33     }
34     dp[0]=1;
35     for(int i=1;i<=m;i++)       //枚举课程
36     {
37       for(int j=n;j>=f[i].s;j--)      //枚举价值,要从大到小推!
38       {
39         for(int k=1;k<=f[i].n;k++)    ////枚举这个物品的个数,如果当前枚举到的价值能放入此物品的话,就加上之前的价值
40         {
41           if(j>=k*f[i].s)
42             dp[j]+=dp[j-k*f[i].s];       //更新数组
43           else
44             break;
45         }
46       }
47     }
48     cout<<dp[n]<<endl;
49   }
50   return 0;
51 }

另一种 从小到大推,别人写的,摘自http://www.lai18.com/content/2463208.html

 1 #include <stdio.h>
 2 #include <math.h>
 3 #include <string.h>
 4 #include <stdlib.h>
 5 #include <iostream>
 6 #include <sstream>
 7 #include <algorithm>
 8 #include <string>
 9 #include <queue>
10 #include <vector>
11 #define maxn 100005
12 #define maxm 50000
13 using namespace std;
14 typedef long long ll;
15 int main()
16 {
17   int T, n, num, a[10], b[10], c1[41], c2[41];
18   //由于1<=num<=8,所以a,b开到10;由于1<=n<=40,所以c1,c2开到41
19   scanf("%d", &T);
20   while (T--)
21   {
22     scanf("%d%d", &n, &num);
23     for (int i = 1;i <= num;i++)
24       scanf("%d%d", &a[i], &b[i]);
25     memset(c1, 0, sizeof(c1));
26     memset(c2, 0, sizeof(c2));
27     c1[0] = 1;//由于本题对每个a[i]有个数限制,所以不能使数组c1初始化1【那样相当于默认学分为1的课程无限个】
28     //但是可以在相乘多项式前多乘一个1,所以赋值c1[0] = 1,同时下面是从i=1开始的
29     for (int i = 1;i <= num;i++)
30     {//i表示乘到了第几项
31       for (int j = 0;j <= n;j++)
32       {
33         for (int k = 0;k + j <= n&&k <= b[i]*a[i];k += a[i])//a[i]是第i个多项式的单个课程学分
34           c2[k + j] += c1[j];
35       }
36       memcpy(c1, c2, sizeof(c1));//c2赋给c1
37       memset(c2, 0, sizeof(c2));//c2清零
38     }
39     printf("%d\n", c1[n]);
40   }
41   return 0;
42 }

还可以用母函数写 可是我不会母函数 有时间去研究研究~

时间: 2024-10-13 17:47:53

HDU 2079 dp解法的相关文章

hdu 2079 选课时间

hdu 2079 选课时间 题意:选的学分总和为n,并且学分为a的课有b种,总共有K(1<=k<=8)种学分不同的课,并且要选的学分最多为40:问选课方案有多少种?(学分相同的课即认为相同) 解法1:朴素背包 求解不重复子结构问题 原本认为只要在完全背包和01背包中把循环do式改成f[v]+=f[v-w]即可,但是发现很多重叠部分:给组小数据就会发现了: 1 3 3 1 2 2 3 3 3 原本f[1]只有1中,但是在二进制中,开始k = 1,f[1] += f[0],f[1]就等于1了,之后

hdu 1548 (dijkstra解法)(一次AC就是爽)

恭喜福州大学杨楠获得[BestCoder Round #4]冠军(iPad Mini一部) <BestCoder用户手册>下载 A strange lift Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 11670    Accepted Submission(s): 4430 Problem Description There is

HDU 4832(DP+计数问题)

HDU 4832 Chess 思路:把行列的情况分别dp求出来,然后枚举行用几行,竖用几行,然后相乘累加起来就是答案 代码: #include <stdio.h> #include <string.h> #include <iostream> using namespace std; typedef long long ll; const ll MOD = 9999991; const int N = 1005; int t, n, m, k, x, y; ll dp1

hdu 3944 dp?

DP? Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 128000/128000 K (Java/Others)Total Submission(s): 1804    Accepted Submission(s): 595 Problem Description Figure 1 shows the Yang Hui Triangle. We number the row from top to bottom 0,1,2,-a

hdu 5389 dp类似背包

http://acm.hdu.edu.cn/showproblem.php?pid=5389 Problem Description Zero Escape, is a visual novel adventure video game directed by Kotaro Uchikoshi (you may hear about ever17?) and developed by Chunsoft. Stilwell is enjoying the first chapter of this

hdu 1025 dp 最长上升子序列

1 //Accepted 4372 KB 140 ms 2 //dp 最长上升子序列 nlogn 3 #include <cstdio> 4 #include <cstring> 5 #include <iostream> 6 using namespace std; 7 const int imax_n = 500005; 8 int dp[imax_n]; 9 int d[imax_n]; 10 int a[imax_n]; 11 int n; 12 int len

HDU 5928 DP 凸包graham

给出点集,和不大于L长的绳子,问能包裹住的最多点数. 考虑每个点都作为左下角的起点跑一遍极角序求凸包,求的过程中用DP记录当前以j为当前末端为结束的的最小长度,其中一维作为背包的是凸包内侧点的数量.也就是 dp[j][k]代表当前链末端为j,其内部点包括边界数量为k的最小长度.这样最后得到的一定是最优的凸包. 然后就是要注意要dp[j][k]的值不能超过L,每跑一次凸包,求个最大的点数量就好了. 和DP结合的计算几何题,主要考虑DP怎么搞 /** @Date : 2017-09-27 17:27

HDU 4901 DP背包

给你n个数,问你将数分成两个数组,S,T ,T 中所有元素的需要都比S任意一个大,问你S中所有元素进行 XOR 操作和 T 中所有元素进行 &操作值相等的情况有多少种. DP背包思路 dpa[i][j][0]  表示从左开始到i,不取i,状态为j的方案数 dpa[i][j][1]  表示从作开始到i,取i,状态为j的方案数 dpb[i][j]      表示从右开始到i,状态为j的方案数 因为S集合一定在T集合的左边,那么可以枚举集合的分割线,并且枚举出的方案要保证没有重复,如果要保证不重复,只

neu1458 方格取数 dp解法

题意: 有N * N个格子,每个格子里有正数或者0,从最左上角往最右下角走,只能向下和向右,一共走两次(即从左上角走到右下角走两趟),把所有经过的格子的数加起来,求最大值SUM,且两次如果经过同一个格子,则最后总和SUM中该格子的计数只加一次. 走两次,所以状态表示要同时表示两次路径.dp[i][j][k][l] 表示第一次走到i,  j,第二次走到k, l得到的最大值,这里i + j == k + l 其实第四维是可以通过前三维算出来的,所以可以去掉 那么dp[i][j][k] 可以通过四种状