整数划分系列

1.nyoj90

描述

将正整数n表示成一系列正整数之和:n=n1+n2+…+nk, 
其中n1≥n2≥…≥nk≥1,k≥1。 
正整数n的这种表示称为正整数n的划分。求正整数n的不 
同划分个数。 
例如正整数6有如下11种不同的划分: 
6; 
5+1; 
4+2,4+1+1; 
3+3,3+2+1,3+1+1+1; 
2+2+2,2+2+1+1,2+1+1+1+1; 
1+1+1+1+1+1。 

输入
第一行是测试数据的数目M(1<=M<=10)。以下每行均包含一个整数n(1<=n<=10)。
输出
输出每组测试数据有多少种分法。
样例输入
1
6
样例输出
11
开始的错误思路:dp[i][j]代表整数i划分的个数不超过j的划分数,但是这样做会有重复划分例如3有3、1+2、2+1、1+1+1。
dp[1][1]=1;
for(i=1; i<=10; i++)
    for(j=1; j<=10; j++)
    {
        if(j==1) dp[i][j]=1;
        else if(j>i) dp[i][j]=0;
        else if(j==i) dp[i][j]=1+dp[i][j-1];
        else
            dp[i][j]=dp[i-1][j-1]+dp[i-1][j];//含单独一个划分和不含单独一个划分
    }

正确做法如下:dp[i][j]代表整数i划分的所有数中最大数不超过j的划分数。
 #include<bits/stdc++.h>
using namespace std;
int dp[15][15];
int main()
{
    int n,m,i,j,t;
    dp[1][1]=1;
    for(i=1; i<=10; i++)
        for(j=1; j<=10; j++)
        {
            if(j==1) dp[i][j]=1;
            else if(i>j) dp[i][j]=dp[i-j][j]+dp[i][j-1];//含j和不含j
            else if(i==j) dp[i][j]=1+dp[i][j-1];
            else dp[i][j]=dp[i][i];
        }
    cin>>t;
    while(t--)
    {
        scanf("%d",&n);
        printf("%d\n",dp[n][n]);
    }
    return 0;
}


因为n很小不超过10,可以用递归写,最多算10!也不会TLE,下面是dfs:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
using namespace std;
typedef long long LL;
int n,ans;
void dfs(int i,int s)
{
    if(s>n) return;
    if(s==n)
    {
        ans++;
        return;
    }
    for(i; i<=10; i++)//保证每次加的数大于等于原来的
    {
        dfs(i,s+i);
    }
}
int main()
{
    int m;
    cin>>m;
    while(m--)
    {
        ans=0;
        cin>>n;
        dfs(1,0);
        cout<<ans<<endl;
    }
}

2.nyoj176:n划分成m个整数的和

dp[i][j]代表i划分成j个数

#include<bits/stdc++.h>
using namespace std;
int dp[105][108];
int main()
{
    int n,m,i,j,t;
    dp[1][1]=1;
    for(i=2; i<=100; i++)
        for(j=1; j<=i; j++)
        {
            if(i==j||j==1) dp[i][j]=1;
            else dp[i][j]=dp[i-1][j-1]+dp[i-j][j];//含1和不含1
        }
    cin>>t;
    while(t--)
    {
        scanf("%d%d",&n,&m);
        printf("%d\n",dp[n][m]);
    }
    return 0;
}
        


3.nyoj279:队花的烦恼

描述

ACM队队花C小+最近在X大OJ上做题,竟发现了一道做不出来的…水题!她快郁闷死了……也许是最近状态不太好吧……她希望大家能帮帮忙:把一个整数分成若干个不为零的整数,问有多少种不同分法。

例:7 3 其中的分法:1 1 5,1 5 1,5 1 1是同一种分法。

输入
有多组测试数据
每组数据都有两个整数n,m(6<=n<=500,2<=m<=6)
n表示该整数,m表示把n分成m份
输出
对每一组测试数据,输出不同的分法数
样例输入
7 3
10 2
20 3
样例输出
4
5
33
注意m<=6即可
#include<bits/stdc++.h>
using namespace std;
int dp[505][8];
int main()
{
    int n,m,i,j;
    dp[1][1]=1;
    for(i=2; i<=500; i++)
        for(j=1; j<=i&&j<=6; j++)
        {
            if(i==j||j==1) dp[i][j]=1;
            else dp[i][j]=dp[i-1][j-1]+dp[i-j][j];
        }
    while(~scanf("%d%d",&n,&m))
    {
        printf("%d\n",dp[n][m]);
    }
    return 0;
}
        




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值