普通母函数(组合)

https://vjudge.net/problem/HDU-1398

#include <cstdio>
using namespace std;
const int maxn= 310;
// c1是保存各项质量砝码可以组合的数目
// c2是中间量,保存每一次的情况
int c1[maxn], c2[maxn],step[20];
int main()
{   int n;
    for(int i=0;i<=17;i++)
        step[i]=i*i;
    while(scanf("%d",&n)!=EOF,n)
    {
        for(int i=0;i<=n;i++)
        {
            c1[i]=1;
            c2[i]=0;
        }
        for(int i=2;i*i<=n;i++)
        {
            for(int j=0;j<=n;j++)
            {
                for(int k=0;k+j<=n;k+=step[i])
                {
                    c2[j+k]+=c1[j];
                }
            }
            for(int j=0;j<=n;j++)
            {
                c1[j]=c2[j];
                c2[j]=0;
            }
        }
        printf("%d\n",c1[n]);
    }
    return 0;
}

https://vjudge.net/problem/HDU-1085
题意: 给你a个一元硬币,b个两元硬币,c个五元硬币,问不能凑出来的最小面额是多少。

#include <cstdio>
#include<string.h>
using namespace std;
const int maxn= 8010;
// c1是保存各项质量砝码可以组合的数目
// c2是中间量,保存每一次的情况
int c1[maxn], c2[maxn],step[5]={0,1,2,5};
int main()
{
    int a,b,c;
    while(scanf("%d%d%d",&a,&b,&c)!=EOF,a+b+c)
    {
        memset(c1,0,sizeof(c1));
        memset(c2,0,sizeof(c2));
        for(int i=0;i<=a;i++)
        {
            c1[i]=1;
        }
        for(int j=0;j<=a;j++)
        {
            for(int k=0;k<=b*2;k+=step[2])
            {
                c2[j+k]+=c1[j];
            }
        }
        for(int i=0;i<=a+b*2;i++)
        {
            c1[i]=c2[i];
            c2[i]=0;
        }
        for(int j=0;j<=a+b*2;j++)
        {
            for(int k=0;k<=c*5;k+=step[3])
            {
                c2[j+k]+=c1[j];
            }
        }
        for(int i=0;i<=a+b*2+c*5;i++)
        {
            c1[i]=c2[i];
            c2[i]=0;
        }
        int j;
        for(j=0;j<=a+b*2+c*5;j++)
        {
            if(c1[j]==0) {
                printf("%d\n",j);
                break;
            }
        }
        if(j==a+b*2+c*5+1) printf("%d\n",j);
    }
    return 0;
}

https://vjudge.net/problem/HDU-1171
题意:有n样物品,每样物品价值是val[ i ],件数是num[ i ]。尽量把这些物品分成两堆使得两边总价值最接近。输出分得的两堆各自的价值,价值大的在前面。
题解:假设物品i的价值为v,数量为n;则该物品的母函数为(1+xv+x2v+...+x(n-1)v+xnv)

#include <cstdio>
#include<string.h>
using namespace std;
const int maxn= 255555;
int c1[maxn], c2[maxn],val[55],num[55];
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF&&n>0)
    {
        memset(c1,0,sizeof(c1));
        memset(c2,0,sizeof(c2));
        int total=0;
        for(int i=1;i<=n;i++) {
                scanf("%d%d",val+i,num+i);
                total+=val[i]*num[i];
        }
        for(int i=0;i<=num[1];i++)
            c1[i*val[1]]=1;

        int curr=num[1]*val[1];
        for(int i=2;i<=n;i++)
        {
            for(int j=0;j<=curr;j++)
            {
                for(int k=0;k<=num[i];k++)
                {
                    c2[j+k*val[i]]+=c1[j];
                }
            }
            curr+=num[i]*val[i];
            for(int j=0;j<=curr;j++)
            {
                c1[j]=c2[j];
                c2[j]=0;
            }
        }
        int j;
        for(j=total/2;j>=0;j--)
        {
            if(c1[j]) break;
        }
        printf("%d %d\n",total-j, j);
    }
    return 0;
}

https://vjudge.net/problem/HDU-1709
题意:有一个天平,有n个砝码,重量分别为wi,求出所有不能用天平测量的重量。
题解:每个砝码可以不用,也可以放左边或者放右边。

#include <cstdio>
#include<string.h>
using namespace std;
const int maxn= 22222;
int c1[maxn], c2[maxn],val[55],ans[maxn];
const int shift=10001;
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        memset(c1,0,sizeof(c1));
        memset(c2,0,sizeof(c2));
        for(int i=1;i<=n;i++)
            scanf("%d",val+i);
        for(int i=-1;i<=1;i++)
            c1[i*val[1]+shift]=1;
        int curr=val[1]+shift,num=0,lef=shift-val[1];
        for(int i=2;i<=n;i++)
        {
            for(int j=lef;j<=curr;j++)
            {
                for(int k=-1;k<=1;k++)
                {
                    c2[j+k*val[i]]+=c1[j];
                }
            }
            curr+=val[i];
            lef-=val[i];
            for(int j=lef;j<=curr;j++)
            {
                c1[j]=c2[j];
                c2[j]=0;
            }
        }
        for(int i=lef;i<=curr;i++)
        {
            if(c1[i]==0&&i-shift>0)
            {
                ans[num++]=i-shift;
            }
        }
        printf("%d\n",num);
        if(num!=0) printf("%d",ans[0]);
        for(int i=1;i<num;i++)
        {
            printf(" %d",ans[i]);
        }
        if(num!=0) printf("\n");

    }
    return 0;
}

https://vjudge.net/problem/HDU-2069
题意:现在有价值为n的硬币,然后你有1,5,10,25,50的小硬币。有多少种方法凑成价值为n的硬币。注意:最多只能使用100个硬币。
题解:与一般母函数不同,一般的母函数是控制每种硬币的数量,或者是不控制,而此题控制的总的金币数目不能超过100,所以开一个二维数组来控制总的硬币的数目。

#include <cstdio>
#include<string.h>
using namespace std;
const int maxn= 260;
int c1[maxn][110], c2[maxn][110];//第一维是系数,第二维是硬币总数
int c3[maxn],val[6]={0,1,5,10,25,50};
int main()
{
    int n;
    memset(c1,0,sizeof(c1));
    memset(c2,0,sizeof(c2));
    for(int i=0;i<=100;i+=val[1])
    {
        c1[i][i]=1;
    }
    for(int i=2;i<=5;i++)
    {
        for(int j=0;j<=250;j++)
        {
            for(int k=0;j+k<=250;k+=val[i])
            {
                for(int p=0;p+k/val[i]<=100;p++)
                {
                    c2[j+k][p+k/val[i]]+=c1[j][p];//控制金币总数不超过100
                }
            }
        }
        for(int j=0;j<=250;j++)
        {
            for(int p=0;p<=100;p++)
            {
                c1[j][p]=c2[j][p];
                c2[j][p]=0;
            }

        }
    }
    memset(c3,0,sizeof(c3));
    for(int i=0;i<=250;i++)
    {
        for(int j=0;j<=100;j++)
        {
            c3[i]+=c1[i][j];
        }
    }
    while(scanf("%d",&n)!=EOF)
    {
        if(n<0) printf("0\n");
       else printf("%d\n",c3[n]);

    }
    return 0;
}

https://vjudge.net/problem/HDU-2152

#include<cstdio>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn=110;
int c1[maxn],c2[maxn];
int lef[maxn],rig[maxn];
//把每种水果的价钱设置为1;则买m个水果相当于买m元水果。
//或者这样理解:买m个水果,水果的个数就为母函数的指数,个数的增值的步长每次都是1
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",lef+i,rig+i);
        }
        memset(c1,0,sizeof(c1));
        memset(c2,0,sizeof(c2));
        for(int i=lef[1];i<=m&&i<=rig[1];i++)
        {
            c1[i]=1;
        }
        int st=min(lef[1],m),ed=min(rig[1],m);
        for(int i=2;i<=n;i++)
        {
            for(int j=st;j<=ed;j++)
            {
                for(int k=lef[i];k<=rig[i];k++)
                {
                    if(j+k<=m){
                        c2[j+k]+=c1[j];
                    }
                    else break;
                }
            }
            st=min(st+lef[i],m);
            ed=min(ed+rig[i],m);
            for(int j=st;j<=ed;j++)
            {
                c1[j]=c2[j];
                c2[j]=0;
            }
        }
        printf("%d\n",c1[m]);
    }
    return 0;
}

https://vjudge.net/problem/HDU-2082
题意:假设有x1个字母A, x2个字母B,..... x26个字母Z,同时假设字母A的价值为1,字母B的价值为2,..... 字母Z的价值为26。那么,对于给定的字母,可以找到多少价值<=50的单词呢?单词的价值就是组成一个单词的所有字母的价值之和,比如,单词ACM的价值是1+3+14=18,单词HDU的价值是8+4+21=33。(组成的单词与排列顺序无关,比如ACM与CMA认为是同一个单词)。

#include <cstdio>
#include<string.h>
using namespace std;
const int maxn=55;
long long c1[maxn],c2[maxn];
int num[30];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        for(int i=1;i<=26;i++)
        {
            scanf("%lld",num+i);
        }
        memset(c1,0,sizeof(c1));
        memset(c2,0,sizeof(c2));
        for(int i=0;i<=num[1];i++){
            c1[i]=1;
        }
        for(int i=2;i<=26;i++)
        {
            for(int j=0;j<=50;j++)
            {
                for(int k=0;j+k*i<=50&&k<=num[i];k++)
                {
                    c2[j+k*i]+=c1[j];
                }
            }
            for(int j=0;j<=50;j++)
            {
                c1[j]=c2[j];
                c2[j]=0;
            }
        }
        long long sum=0;
        for(int i=1;i<=50;i++)
            sum+=c1[i];
        printf("%lld\n",sum);
    }
    return 0;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339

推荐阅读更多精彩内容

  • (一)巴什博弈只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个。最后取光者得胜。显然,...
    Gitfan阅读 904评论 0 0
  • https://vjudge.net/problem/HDU-3980题意: 两个人在一个由 n 个玻璃珠组成的...
    Gitfan阅读 903评论 0 0
  • 背景 一年多以前我在知乎上答了有关LeetCode的问题, 分享了一些自己做题目的经验。 张土汪:刷leetcod...
    土汪阅读 12,716评论 0 33
  • 今天主要读诗,会了很多但不愿意指读,昨晚我说我老了眼花看不见,你帮我指,你指到哪我就读哪,兜宝很负责的指给我,有的...
    兜妈妈阅读 311评论 0 0
  • 早上我起床,妈妈就干活去了,等我给宝宝穿衣洗漱后,就匆匆吃早饭,因为我们计划今天出门——上街买菜。 熙熙攘攘的人群...
    云卷云舒2017阅读 182评论 0 0