1.基础dp 整数划分:
1.1基础题目1:输入一个正数n,输出所有和为n连续正数序列。
例如输入15,由于1+2+3+4+5=4+5+6=7+8=15,所以输出3个连续序列1-5、4-6和7-8。
思路:等差数列的求和,an=a1+k-1 ;(a1+a1+k-1)*k=2*n; 先求出k即找出2*n的因子;
解的集合与 2n的在[2,sqrt(2n)]区间的几个因子相关。每个因子可能对应一个解-----a1;也可能没有解;等差数列的性质 假设 a1最小为1,则(a1+a1+k-1)*k/2=(k+1)*k/2;要满足(k+1)*k不超过2*n;
即解最大为sqrt(2*n)+1;最小为2;k可以理解为等差序列中元素的个数。
伪代码:1) 令imax=sqrt(2*n)+1;
2) 令i=2~imax;
3) 如果i可以被(2*n)整除,令temp=2*n-i*i+i;之后判断如果2*i也可以被temp整除,(说明可以a1有解,即a1= temp/(2*i) );
4) 令start=temp/(2*i);end=start+i-1;
5) 输出 j=start~end;
6) 循环 3)-5)
C语言实现:
#include<stdio.h>
#include<math.h>
int main()
{
int n,temp,start,end;
while(~scanf("%d",&n))
{
int imax=(int)sqrt(n*2)+1;
for(int i=2;i<imax;i++)
{
if((n*2)%i==0)
{
temp=n*2-i*i+i;
if(temp%(i*2)==0)
{
start=temp/(i*2);
end=start+i-1;
printf("%d = ",n);//打印输出
for(int j=start;j<end;j++)
printf("%d+",j);
printf("%d\n",end);
}
}
}
}
}1.1基础题目2_跳台阶问题(Fibonacci序列)
题目:一个台阶总共有n级,如果一次可以跳1级,也可以跳2级。求总共有多少总跳法,并分析算法的时间复杂度;
f(1)=1; f(2)=2;f(n)=f(n-1)+f(n-2),(n>2);
//递归代码
int fib(int n)
{
if(n==1)return 1;
if(n==2)return 2;
return fib(n-1)+fib(n-2);
}1.1正题——整数划分
是指把一个正整数n写成如下形式:
n=m1+m2+...+mi; (其中mi为正整数,并且1 <= mi <= n),则{m1,m2,...,mi}为n的一个划分。
如果{m1,m2,...,mi}中的最大值不超过m,即max(m1,m2,...,mi)<=m,则称它属于n的一个m划分。这里我们记n的m划分的个数为f(n,m);
例如但n=4时,他有5个划分,{4},{3,1},{2,2},{2,1,1},{1,1,1,1};
注意4=1+3 和 4=3+1被认为是同一个划分。
该问题是求出n的所有划分个数,即f(n, n)。
下面我们考虑求f(n,m)的方法;
根据n和m的关系,考虑以下几种情况:
(1)当 n = 1 时,不论m的值为多少(m > 0 ),只有一种划分即 { 1 };
(2)当 m = 1 时,不论n的值为多少,只有一种划分即 n 个 1,{ 1, 1, 1, ..., 1 };
(3)当 n = m 时,根据划分中是否包含 n,可以分为两种情况:
(a). 划分中包含n的情况,只有一个即 { n }
(b). 划分中不包含n的情况,这时划分中最大的数字也一定比 n 小,即 n 的所有 ( n - 1 ) 划分。
因此 f(n, n) = 1 + f(n, n-1);
(4) 当 n < m 时,由于划分中不可能出现负数,因此就相当于 f(n, n);
(5) 但 n > m 时,根据划分中是否包含最大值 m,可以分为两种情况:
(a). 划分中包含 m 的情况,即 { m, { x1, x2, ..., xi } }, 其中 { x1, x2, ..., xi } 的和为 n - m,可能再次出现 m,因此是(n - m)的 m 划分,因此这种划分个数为 f(n-m, m);
(b). 划分中不包含 m 的情况,则划分中所有值都比 m 小,即 n 的 ( m - 1 ) 划分,个数为 f(n, m - 1);
因此 f(n, m) = f(n - m, m) + f(n, m - 1);
问题1:求整数划分的个数
//递归代码
//递归代码
int div(int n,int m)
{
if(n==1||m==1)
return 1;
if(n<m)
return div(n,n);
if(n==m)
return 1+div(n,m-1);
if(n>m)
return div(n-m,m)+div(n,m-1);
}//打表法,记忆搜索
#include<stdio.h>
#include<string.h>
int a[100][100];//记忆化搜索
int fun(int n,int m)
{
if(a[n][m]>0)
{ // printf("Use the a[%d][%d]\n",n,m);
return a[n][m];
}
if(n==1)
return a[1][m]=1;
if(m==1)
return a[n][1]=1;
if(n<m)
return a[n][n]=fun(n,n);
if(n==m)
return a[n][m]=fun(n,m-1)+1;
if(n>m)
return a[n][m]=fun(n-m,m)+fun(n,m-1);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(a,-1,sizeof(a));
int n;
scanf("%d",&n);
printf("%d\n",fun(n,n));
}
return 0;
}问题 2:输出整数划分的元素?
#include<stdio.h>
#include<string.h>
int tp;
int div(int n,int m)
{
if(n==1||m==1){
if(n==1)
printf("1\n");
else if(m==1)
{
int j=tp-n;
if(j!=0)
printf("%d ",j);
while(n--)
printf("1 ");
printf("\n");
}
return 1;
}
if(n<m){
//printf("%d\n",n);
return div(n,n);
}
if(n==m)
{
printf("%d\n",n);
return 1+div(n,m-1);
}
if(n>m){
printf("%d ",m);
return div(n-m,m)+div(n,m-1);
printf("\n");
}
}
int main()
{
int n;
int t;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
tp=n;
printf("%d\n",div(n,n));
}
}NYOJ176整数划分(二)
时间限制:1000 ms | 内存限制:65535 KB
难度:3
描述
把一个正整数m分成n个正整数的和,有多少种分法?
例:把5分成3个正正数的和,有两种分法:
1 1 3
1 2 2
输入
第一行是一个整数T表示共有T组测试数据(T<=50)
每组测试数据都是两个正整数m,n,其中(1<=n<=m<=100),分别表示要拆分的正数和拆分的正整数的个数。
输出
输出拆分的方法的数目。
样例输入
2
5 2
5 3
样例输出
2
2
#include<stdio.h>
int dp[101][101]={1};
int main()
{
for(int i=1;i<101;i++)
for(int j=1;j<=i;j++)
dp[i][j]=dp[i-1][j-1]+dp[i-j][j];
int t,n,m;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
printf("%d\n",dp[n][m]);
}
return 0;
}整数划分终极版
NYOJ571整数划分(三)
时间限制:1000 ms | 内存限制:65535 KB
难度:5
描述
整数划分是一个经典的问题。请写一个程序,完成以下要求。
输入
每组输入是两个整数n和k。(1 <= n <= 50, 1 <= k <= n)
输出
对于输入的 n,k;
第一行: 将n划分成若干正整数之和的划分数。
第二行: 将n划分成k个正整数之和的划分数。
第三行: 将n划分成最大数不超过k的划分数。
第四行: 将n划分成若干个 奇正整数之和的划分数。
第五行: 将n划分成若干不同整数之和的划分数。
第六行: 打印一个空行
样例输入
5 2
样例输出
7
2
3
3
3
提示
样例输出提示:
1.将5划分成若干正整数之和的划分为: 5, 4+1, 3+2, 3+1+1, 2+2+1, 2+1+1+1, 1+1+1+1+1
2.将5划分成2(k个)个正整数之和的划分为: 3+2, 4+1
3.将5划分成最大数不超过2的划分为: 1+1+1+1+1, 1+1+1+2, 1+2+2
4.将5划分成若干 奇正整数之和的划分为: 5, 1+1+3, 1+1+1+1+1
5.将5划分成若干不同整数之和的划分为: 5, 1+4, 2+3
#include<stdio.h>
int d1[101][101];//若干整数之和与最大不超过 k的划分
int d2[101][101];//将 n划分成 k个不同整数之和的划分
int d4[101][101];//将 n划分成若干奇整数之和的划分
int d5[101][101];//将 n划分成若干不同整数之和的划分
void divone(){//将 i划分为最大元素不超过 j的划分个数
int i,j;
d1[0][0]=1;
for(i=0;i<101;++i)
for(j=1;j<101;++j)
{
if(i<j)d1[i][j]=d1[i][i];
else d1[i][j]=d1[i-j][j]+d1[i][j-1];
}
}
void divtwo(){//将 i划分成 j个不同整数之和的划分
int i,j;
d2[0][0]=1;
for(i=1;i<=100;++i)
for(j=1;j<=i;++j)
d2[i][j]=d2[i-1][j-1]+d2[i-j][j];
}
void divfour(){//将 i划分成若干奇整数之和的划分
int i,j;
d4[0][0]=1;
for(i=0;i<101;++i)
for(j=1;j<101;++j)
{
if(j&1){
if(j>i)d4[i][j]=d4[i][i];
else d4[i][j]=d4[i-j][j]+d4[i][j-1];
}
else d4[i][j]=d4[i][j-1];
}
}
void divfive(){//将 i划分成若干不同整数之和的划分
int i,j;
d5[0][0]=1;
for(i=0;i<=100;++i)
for(j=1;j<=100;++j)
if(j>i)d5[i][j]=d5[i][i];
else d5[i][j]=d5[i-j][j-1]+d5[i][j-1];//与divone()不同_d5[i-j][j-1]
}
int main()
{
int n,k;
divone();
divtwo();
divfour();
divfive();
while(~scanf("%d%d",&n,&k))
{
printf("%d\n%d\n%d\n%d\n%d\n",d1[n][n],d2[n][k],d1[n][k],d4[n][n],d5[n][n]);
}
}NYOJ746整数划分(四)
时间限制:1000 ms | 内存限制:65535 KB
难度:3
描述
暑假来了,hrdv 又要留学校在参加ACM集训了,集训的生活非常Happy(ps:你懂得),可是他最近遇到了一个难题,让他百思不得其解,他非常郁闷。。亲爱的你能帮帮他吗?
问题是我们经常见到的整数划分,给出两个整数 n , m ,要求在 n 中加入m - 1 个乘号,将n分成m段,求出这m段的最大乘积
输入
第一行是一个整数T,表示有T组测试数据
接下来T行,每行有两个正整数 n,m ( 1<= n < 10^19, 0 < m <= n的位数);
输出
输出每组测试样例结果为一个整数占一行
样例输入
2
111 2
1111 2
样例输出
11
121
代码如下:
//先用两重循环计算a[i][j],表示i到j这段子串的数值,dp[i][j]表示到i的这个前缀子串分为j部分的乘积的最大值,
//则有dp[i][j]=max(dp[i][j],dp[k][j-1]*a[k+1][i]),注意j-2<=k<i;
#include<stdio.h>
#define LL long long
#include<cstring>
#include<algorithm>
using namespace std;
char s[25];
LL a[25][25];
LL dp[25][25];
int main()
{
int t,m,i,j,k;
scanf("%d",&t);
while(t--)
{
scanf("%s%d",s,&m);
int len=strlen(s);
memset(a,0,sizeof(a));
memset(dp,0,sizeof(dp));
for(i=0;i<len;i++)
{
a[i][i]=s[i]-'0';
for(j=i+1;j<len;j++)
{
a[i][j]=a[i][j-1]*10+(LL)(s[j]-'0');
}
}
for(i=0;i<len;i++)
{
dp[i][1]=a[0][i];
for(j=2;j<=m;j++)
{
for(k=j-2;k<i;k++)
{
dp[i][j]=max(dp[i][j],dp[k][j-1]*a[k+1][i]);
}
}
}
printf("%lld\n",dp[len-1][m]);
}
return 0;
}

1530

被折叠的 条评论
为什么被折叠?



