• [題解]2019-2-28考試:天平問題(背包和母函數)


    前言:

    第一篇题解,寫點自己在網上搜到的東西,雖然沒什麼卵用......

    不會排版還要慢慢學......

    作為一個菜雞可能以後發的大多是歌曲推薦(???或者是奇奇怪怪的東西(???


     題目其實在hdu 1709,有多組數據

    題面:

    小C为了试验小X,便为物竞的小X出了一道物理相关的题:现在给出n个质量的砝码,问小X能称出多少种质量的物品,可是总有好事者想要破坏,于是乎,n达到了500,远远超出了小X能够承受的范围,锲而不舍的他决定寻求你们的帮助。

    30%:n <=10
    60%: n<=100
    100%: n<=500 数据保证砝码的质量之和不超过20000

    樣例輸入:                   樣例輸出:

    3                                 13

    1

    3

    9

    注意:天平有两边,两边均可放。


    一、01背包

    狀態轉移方程:f[ j ]=f[ j-a[ i ] ]或f[ j+a[ i ] ]

    至於減法只要減一下取個絕對值就可以了

     手測了一點點樣例,應該沒問題,要是有錯我再改

    2019-03-02 17:43:36 AC

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    int n,a[505],sum;
    int f[20005];
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]),sum+=a[i];
        }
        
        f[0]=1;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=sum;j++)
            if(f[j+a[i]]) f[j]=1;
            
            for(int j=sum;j>=1;j--)
            if(f[(int)abs(j-a[i])]) f[j]=1;
        }
        
        int ans=0;
        for(int i=1;i<=sum;i++)ans+=f[i];
    
        printf("%d",ans);
        return 0;
    }

    2019-03-01 00:24:50

    二、普通母函數

     自己在網上看的博客,就是整理一下,寫一些我覺得比較重要的

    原文:https://blog.csdn.net/yu121380/article/details/79914529

    例題:有1克、2克、3克、4克的砝码各一 枚,能称出哪几种重量?每种重量各有几种可能方案?

    我們先在1g和2g間枚舉:(以下為引用)

    (使用1g || 不使用1g)&&(使用2g || 不使用2g)

    =使用1g&&使用2g || 不使用1g&&使用2g || 使用1g&&不使用2g || 不使用1g&&不使用2g

    每个用 “||”分开的一项都是一种方案。“&&”表示选择第一项的情况下有选择了第二项。

    大家可以发现这个表达式和一种表达式很像,没错,如果把“||”看成加法,“&&”看成乘法,和多项式的乘法一模一样。那么我们直觉的想到,有没有可能用多项式乘法来表示组合的情况呢?

    我们再来看题目,题目需要的是几种砝码组合后的重量,是一个加法关系,但是在上式中“&&”是一种类似于乘法的运算关系,这怎么办呢?

    有没有什么这样一种运算关系,以乘法的形式运算,但是结果表现出类似于加法的关系呢?正好有一个,那就是幂运算。Xm 乘上Xn结果是Xm+n,他完美的符合了我们的要求。那么以次数表示砝码的质量, 就可以以多项式的形式表示砝码组合的所有方案。

    还是以前两个砝码为例说明,表示1g砝码的两种状态的多项式就是(x0+x1),表示2g的就是(x0+x2),x0表示没有使用砝码,所以重量为0,当然了因为x0 =1,所以也可以写成1,后面为了方便我会这么写。注意,砝码的质量是以次数表示的,而不是直觉上的用下标表示为x1,x2。这点很重要,不然的话就无法表现出幂运算的关系了。

    (x0+x1)*(x0+x2)

    =x0*x0 + x1*x0 + x0*x2 + x1*x2

    =x0 + x1 + x2 + x3

    很显然,有四种方案,0g、1g、2g、3g,结果与我们穷举的结果相同,而如果结果中有相同的项,那么合并同类项后每一项的系数就是这种重量有几种实现方案,这会在我们用此方法解决4个砝码问题的时候得到证明。

    那么接下来试试用这种表达式表示4个砝码的组合情况

    (x0+x1)* (x0+x2) * (x0+x3)* (x0+x4)

    =x0 + x1 + x2 + 2x3 + 2x4 + 2x5 + 2x6 + 2x7 + x8+ x9 + x10

    解釋的非常清楚了,關於這道題的不同點是左右都能放砝碼,考慮減小的情況

    所以這道題转化为(1+x^a[1])*(1+x^a[2])*(1+x^a[3])……(1+x^a[n])

    接下來代碼,細節注釋在代碼里

    然而代碼仍然是抄的,因為還不太理解,反正先發出來就是了

    2019-03-02 17:43:36 AC

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int n,a[505],sum,ans;//sum为所有砝码的和也就是上界 
    int sup[20005],temp[20005];
    //sup为當前運算后的結果(被乘多項式),存的是多项式的系数
    //下标為多項式的次數,也就是砝码的重量 
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]),sum+=a[i];
        for(int i=0;i<=a[1];i+=a[1])sup[i]=1;
        //初始化第一個多項式,也就是用a[1]的多項式
        for(int i=2;i<=n;i++){//生成后续的第i个多项式
            for(int j=0;j<=sum;j++)//遍历当前结果多项式的第j項,與第i個多項式相乘 
            for(int k=0;j+k<=sum && k<=a[i];k+=a[i]){//遍歷第i個多項式的每一項 
                if(k>=j)
                temp[k-j]+=sup[j];
                else temp[j-k]+=sup[j];
                temp[j+k]+=sup[j];
            }
            for(int j=0;j<=sum;j++){//將臨時的結果覆蓋當前結果,同時初始化temp 
                sup[j]=temp[j];
                temp[j]=0;
            }
        }
        for(int i=1;i<=sum;i++)
        if(sup[i]!=0)ans++;//如果這一項係數為0,代表不能拼成 
        printf("%d",ans);
    }

    寫博客有點耗時間啊,以後還是有把握了再發博客吧,或者不務正業什麼的

    2019-03-01 19:57:54

  • 相关阅读:
    《JavaScript高级程序设计》读书笔记(十):本地对象Date
    JavaScript计算字符串中每个字符出现的次数
    JavaScript单元测试ABC
    ASP.NET MVC3 AJAX 上传图片示例
    canvas标签的width和height以及style.width和style.height的区别
    分享一个自定义的 console 类,让你不再纠结JS中的调试代码的兼容
    《JavaScript高级程序设计》阅读笔记(十四):继承机制的实现
    从此不再惧怕URI编码:JavaScript及C# URI编码详解
    Levenshtein算法的JavaScript实现
    《JavaScript高级程序设计》阅读笔记(十五):浏览器中的JavaScript
  • 原文地址:https://www.cnblogs.com/superminivan/p/10454189.html
Copyright © 2020-2023  润新知