• 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
  • 相关阅读:
    Shell 中 -n 条件判断的使用
    Linux shell 中(()) [] [[ ]] 的使用
    Linux 利用黑洞实现“取消在控制台输出日志”
    Hadoop DataNode 多目录磁盘扩展配置
    Linux 挂载硬盘
    css 对元素在文档中的排列的影响
    vue-route 基础
    javaScript 琐碎
    javaScript 事件流---冒泡 && 捕获
    页面优化---利用浏览器缓存
  • 原文地址:https://www.cnblogs.com/acm-jing/p/4252652.html
Copyright © 2020-2023  润新知