hdu acm steps Big Event in HDU

上网搜了一下这道题的解法,主要有两个方法,一种是采用母函数的方法,一种是采用0/1背包的方法。

先说一下母函数,即生成函数,做个比喻,母函数就是一个多项式前面的系数的一个整体的集合,而子函数就是这个多项式每一项前面的系数。主要用于解决组合问题,类似于钱币的组合问题。利用母函数解题时,首先要写出表达式,通常是多项式的乘积形式,类似于:(x^(v[K]*n1[K])+x^(v[K]*(n1[K]+1))+x^(v[K]*(n1[K]+2))+...+x^(v[K]*n2[K]))。

例如,对于有n种物品,如果第i种物品有ki个,我们可以列式n个项相乘 (x^0+x^1+...x^k1)*(x^0+x^1+...x^k2)*...*(x^0+x^1+...x^kn),每一项表示对于第i件物品,可以有(x^0+x^1+...x^ki)中取法,【注意系数都为1,因为同种物品取i件,它的取法是1】多项相乘:因为取m件物品这件事实要分为对n种物品各取分别取1次【0~ki个】,  是组合计数的乘法原理, x^m 的系数是组合成m件物品的所有方案数

一、母函数解题的核心就是要找到:

k(对应具体问题中物品的种类数)、

v[i](表示该乘积表达式第i个因子的权重,对应于具体问题的每个物品的价值或者权重)、

n1[i](表示该乘积表达式第i个因子的起始系数,对应于具体问题中的每个物品的最少个数,即最少要取多少个)、

n2[i](表示该乘积表达式第i个因子的终止系数,对应于具体问题中的每个物品的最多个数,即最多要取多少个)。

之后迭代计算,并将结果放在一个数组a中。其中a[i]表示权重为i的组合数。

二、母函数对应的具体题型:

主要是普通型母函数,主要用在组合和整数拆分问题上。

关于母函数的百度百科:http://baike.baidu.com/view/2415279.htm

三、模板

先贴一下我收集到的母函数模板:

模板一

 1     //a为计算结果,b为中间结果。  
 2     int a[MAX],b[MAX];  
 3     //初始化a  
 4     memset(a,0,sizeof(a));  
 5     a[0]=1;  
 6     for (int i=1;i<=17;i++)//循环每个因子  
 7     {  
 8         memset(b,0,sizeof(b));  
 9         for (int j=n1[i];j<=n2[i]&&j*v[i]<=P;j++)//循环每个因子的每一项  ,p为可能的最大指数
10             for (int k=0;k+j*v[i]<=P;k++)//循环a的每个项  
11                 b[k+j*v[i]]+=a[k];//把结果加到对应位  
12     memcpy(a,b,sizeof(b));//b赋值给a  
13     }  

 有一个last变量记录当前的最大指数,可以提高程序的效率:

模板二:

 1 //初始化a,因为有last,所以这里无需初始化其他位
 2 a[0]=1;
 3 int last=0;
 4 for (int i=0;i<K;i++)
 5 {
 6     int last2=min(last+n[i]*v[i],P);//计算下一次的last
 7     memset(b,0,sizeof(int)*(last2+1));//只清空b[0..last2]
 8         for (int j=n1[i];j<=n2[i]&&j*v[i]<=last2;j++)//这里是last2
 9             for (int k=0;k<=last&&k+j*v[i]<=last2;k++)//这里一个是last,一个是last2
10                 b[k+j*v[i]]+=a[k];
11    memcpy(a,b,sizeof(int)*(last2+1));//b赋值给a,只赋值0..last2
12     last=last2;//更新last
13 }

因为刚刚接触到acm,最近做的事简单的背包专题,所以此处仅附上背包的思路和解法:

思路:将背包的容量定为所有物品总价值的一半,然后就是0/1背包问题,dp[half]中存储的就是较小的半份。其中,dp[j]表示选前i间物品时,预算为j时背包中装的最大总价值。

状态转移方程为:dp[j]=max{dp[j],dp[j-f[i].v]+f[i].v};

 1 #include"iostream"
 2 #include"stdio.h"
 3 #include"algorithm"
 4 #include"string.h"
 5 #include"cmath"
 6 #define mx 105
 7 using namespace std;
 8 int dp[300000];//注意dp数组的大小
 9 struct node
10 {
11     int v;
12     int c;
13 }f[mx];
14 bool cmp(const node a,const node b)
15 {
16     if(a.v!=b.v) return a.v<b.v;
17 }
18 int main()
19 {
20     int n,i,j,k;
21     while(cin>>n,n>0)
22     {
23           int sum=0,half;
24         for(i=0;i<n;i++)
25         {
26             cin>>f[i].v>>f[i].c;
27             sum+=f[i].v*f[i].c;
28         }
29         half=sum/2;
30         sort(f,f+n,cmp);
31         memset(dp,0,sizeof(dp));
32         for(i=0;i<n;i++)
33         {
34             for(k=1;k<=f[i].c;k++)
35             {
36                 for(j=half;j>=f[i].v;j--)
37                 {
38                     if(dp[j]<dp[j-f[i].v]+f[i].v) dp[j]=dp[j-f[i].v]+f[i].v;
39                 }
40             }
41         }
42         cout<<sum-dp[half]<<' '<<dp[half]<<endl;
43     }
44     return 0;
45 }
View Code
原文地址:https://www.cnblogs.com/acm-jing/p/4252652.html