hdu acm steps Big Event in HDU
2015-01-27 13:15
309 查看
上网搜了一下这道题的解法,主要有两个方法,一种是采用母函数的方法,一种是采用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
三、模板
先贴一下我收集到的母函数模板:
模板一
有一个last变量记录当前的最大指数,可以提高程序的效率:
模板二:
因为刚刚接触到acm,最近做的事简单的背包专题,所以此处仅附上背包的思路和解法:
思路:将背包的容量定为所有物品总价值的一半,然后就是0/1背包问题,dp[half]中存储的就是较小的半份。其中,dp[j]表示选前i间物品时,预算为j时背包中装的最大总价值。
状态转移方程为:dp[j]=max{dp[j],dp[j-f[i].v]+f[i].v};
View Code
先说一下母函数,即生成函数,做个比喻,母函数就是一个多项式前面的系数的一个整体的集合,而子函数就是这个多项式每一项前面的系数。主要用于解决组合问题,类似于钱币的组合问题。利用母函数解题时,首先要写出表达式,通常是多项式的乘积形式,类似于:(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
三、模板
先贴一下我收集到的母函数模板:
模板一
//a为计算结果,b为中间结果。 int a[MAX],b[MAX]; //初始化a memset(a,0,sizeof(a)); a[0]=1; for (int i=1;i<=17;i++)//循环每个因子 { memset(b,0,sizeof(b)); for (int j=n1[i];j<=n2[i]&&j*v[i]<=P;j++)//循环每个因子的每一项 ,p为可能的最大指数 for (int k=0;k+j*v[i]<=P;k++)//循环a的每个项 b[k+j*v[i]]+=a[k];//把结果加到对应位 memcpy(a,b,sizeof(b));//b赋值给a }
有一个last变量记录当前的最大指数,可以提高程序的效率:
模板二:
//初始化a,因为有last,所以这里无需初始化其他位 a[0]=1; int last=0; for (int i=0;i<K;i++) { int last2=min(last+n[i]*v[i],P);//计算下一次的last memset(b,0,sizeof(int)*(last2+1));//只清空b[0..last2] for (int j=n1[i];j<=n2[i]&&j*v[i]<=last2;j++)//这里是last2 for (int k=0;k<=last&&k+j*v[i]<=last2;k++)//这里一个是last,一个是last2 b[k+j*v[i]]+=a[k]; memcpy(a,b,sizeof(int)*(last2+1));//b赋值给a,只赋值0..last2 last=last2;//更新last }
因为刚刚接触到acm,最近做的事简单的背包专题,所以此处仅附上背包的思路和解法:
思路:将背包的容量定为所有物品总价值的一半,然后就是0/1背包问题,dp[half]中存储的就是较小的半份。其中,dp[j]表示选前i间物品时,预算为j时背包中装的最大总价值。
状态转移方程为:dp[j]=max{dp[j],dp[j-f[i].v]+f[i].v};
#include"iostream" #include"stdio.h" #include"algorithm" #include"string.h" #include"cmath" #define mx 105 using namespace std; int dp[300000];//注意dp数组的大小 struct node { int v; int c; }f[mx]; bool cmp(const node a,const node b) { if(a.v!=b.v) return a.v<b.v; } int main() { int n,i,j,k; while(cin>>n,n>0) { int sum=0,half; for(i=0;i<n;i++) { cin>>f[i].v>>f[i].c; sum+=f[i].v*f[i].c; } half=sum/2; sort(f,f+n,cmp); memset(dp,0,sizeof(dp)); for(i=0;i<n;i++) { for(k=1;k<=f[i].c;k++) { for(j=half;j>=f[i].v;j--) { if(dp[j]<dp[j-f[i].v]+f[i].v) dp[j]=dp[j-f[i].v]+f[i].v; } } } cout<<sum-dp[half]<<' '<<dp[half]<<endl; } return 0; }
View Code
相关文章推荐
- HDOJ_ACM_Big Event in HDU
- ACM BigEventinHDU
- HDU 1171 Big Event in HDU
- HDU1171_Big Event in HDU_母函数
- HDU 1171 Big Event in HDU
- HDU 1171 Big Event in HDU
- HDU 1171 Big Event in HDU
- hdu 1171 Big Event in HDU
- hdu 1171 Big Event in HDU (母函数)
- 杭电 1171 Big Event in HDU
- HDU1171 Big Event in HDU,母函数,终极模板
- HDOJ Big Event in HDU 多重背包
- HDU Big Event in HDU
- HDU1171 Big Event in HDU
- HDU 1171 Big Event in HDU
- hdu Big Event in HDU
- HDOJ HDU 1171 Big Event ACM 1171 IN HDU
- HDU 1171 Big Event in HDU
- HDOJ 1171 Big Event in HDU解题报告
- hdu 1171 Big Event in HDU(多重背包可行性)