HDU-1028 Ignatius and the Princess III

6 篇文章 0 订阅
3 篇文章 0 订阅

HDU-1028

题意

输入一个整数n,要求输出n的分拆数。

思路一

母函数,要求n的分拆数,就相当于有n种面值的钱币各无数张,面值为1~n,问你用这些钱币组成n元的方案数。
设用n种面值的钱币组成k元的方案数为ak,则序列a0,a1,a2…ak…an的生成函数为
g(x)=a0+a1*x+a2*x^2+…+ak*x^k+…+an*x^n+……
同时
g(x)=(1+x+x^2+x^3+…+x^n)(1+x^2+x^4+…)(1+x^3+x^6+…)…(1+x^n)…
本题所求的答案即为g(x)中x^n的系数an。

#include <iostream>
using namespace std;
const int maxn = 130;
// c1是保存各项质量砝码可以组合的数目
// c[i]最终结果中代表x^i的系数
// c2是中间量,保存每一次的情况
int c1[maxn], c2[maxn];
int main()
{
    int n;
    int i, j, k;
    while(cin >> n)
    {
        for(i=0; i<=n; ++i) 
        {
            c1[i] = 1;
            c2[i] = 0;
        }
        for(i=2; i<=n; ++i) 
        {
            for(j=0; j<=n; ++j)  
                for(k=0; k+j<=n; k+=i)  
                    c2[j+k] += c1[j];
            for(j=0; j<=n; ++j) 
            {
                c1[j] = c2[j];
                c2[j] = 0;
            }
        }
        cout << c1[n] << endl;
    }
    return 0;
}

思路二

线性dp,二维数组dp[n][m],其中n为要划分的正整数,m是划分中的最大加数(当m > n时,最大加数为n)
1.首先, dp[i][1]和dp[1][j]=1,不难理解
2.下面看一看m 和 n的关系。它们有三种关系
(1) m > n
在整数划分中实际上最大加数不能大于n,因此在这种情况可以等价为dp[n][n];
(2) m = n
这种情况可用递归表示为dp[n][m-1] + 1,从以上例子中可以看出,就是最大加
数为m和小于m的划分之和
(3) m < n
这是最一般的情况,在划分的大多数时都是这种情况。
dp[n][m]=dp[n][m-1]+dp[n-m][m]

#include<iostream>
using namespace std;
const int maxn=130;
int dp[maxn][maxn];
int main()
{
    int n,i,j;
    for(i=0;i<=120;i++)
    {
        dp[i][1]=1;
        dp[1][i]=1;
    }
    for(i=2;i<=120;i++)
        for(j=2;j<=120;j++)
        {
            if(j>i)
                dp[i][j]=dp[i][i];
            if(j==i)
                dp[i][j]=dp[i][j-1]+1;
            if(j<i)
                dp[i][j]=dp[i][j-1]+dp[i-j][j];
        }
    while(cin>>n)
        cout<<dp[n][n]<<endl;
    return 0;
}

思路三

背包的思想,我们用dp[n]表示用这些硬币组成n的方法总数,然后随着钱币种类的增加来更新dp[]的值,也就是最外面的一层循环for(i :1–>n)开始初始化的时候没有钱币,然后新来了面值为1的钱币,接着又来了面值为2的钱币。
显然,每新增加一种面值的钱币,dp[]的值一定在增加,新的dp[] = 未新增前的dp[] + dp[1件新增钱币] + dp[2件新增钱币] + dp[3件新增钱币] +…….dp[k件新增钱币]
由于for里用了完全背包里的顺序,for(j = c[i]; j <= n; j++),所以dp[j] += dp[j - c[i]];中的dp[j - c[i]]已经是有k件新增钱币的状态了。

#include<iostream>
using namespace std;
const int maxn=130;
int dp[maxn];
int main()
{
    int n,i,j;
    dp[0]=1;
    for(i=1;i<=120;i++)
        for(j=i;j<=120;j++)
            dp[j]+=dp[j-i];
    while(cin>>n)
        cout<<dp[n]<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值