1. 程式人生 > >動態規劃-整數劃分

動態規劃-整數劃分

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=sqrt2*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+12.將5劃分成2k個個正整數之和的劃分為: 3+2, 4+13.將5劃分成最大數不超過2的劃分為: 1+1+1+1+1, 1+1+1+2, 1+2+24.將5劃分成若干 奇正整數之和的劃分為: 5, 1+1+3, 1+1+1+1+15.將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集訓了,集訓的生活非常Happyps:你懂得),可是他最近遇到了一個難題,讓他百思不得其解,他非常鬱悶。。親愛的你能幫幫他嗎?

      問題是我們經常見到的整數劃分,給出兩個整數 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],表示ij這段子串的數值,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;
}






相關推薦

動態規劃-整數劃分

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;

動態規劃劃分數 復習

pan 動態規劃 namespace str size esp LV oid sin #include <iostream> #include <algorithm> using namespace std; const int max

動態規劃劃分兩個和相同的子集

題目描述: 給一 只含有正整數的非空陣列, 找到這個陣列是否可以劃分為 兩個 元素和相等的子集。 注意事項: 所有陣列元素不超過100. 陣列大小不超過200. 樣例: 給一陣列 [1, 5, 11, 5] , 返回 true , 兩個子集:[1, 5, 5], [11

動態規劃劃分動態規劃:矩陣鏈乘 poj 1651 Multiplication Puzzle

題意:給你n個數,進行如下操作,問最小值              For example, if cards in the row contain numbers 10 1 50 20 5, pla

動態規劃_百煉 4117 簡單的整數劃分問題

出口 sta pre color 劃分 stack 大於 iostream 規劃 1 #define _CRT_SECURE_NO_WARNINGS 2 #include <stdio.h> 3 #include <math.h> 4

【DP_動態規劃整數劃分

題目連結:http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=90 整數劃分 時間限制:3000 ms  |  記憶體限制:65535 KB 難度:3 輸入 第一行是測試資料的數目M(1&

整數劃分-劃分數(DP動態規劃

給你一個正整數n,讓你計算出n的m劃分有幾種方法。思路:定義dp[i][j]為i的j劃分,即將i劃分為j個數字之和的方案數。1:當j<=i時,此時,劃分個數不超過i,此時是正常的劃分。     劃分的結果一定只有兩種型別:一種是j個數字,都大於0。另一種是有0,即不夠劃

整數劃分問題的動態規劃演算法

/* Name: 整數劃分問題 Copyright: Author: 巧若拙 Date: 06-04-17 09:02 Description: 整數劃分問題是演算法中的一個經典命題之一,有關這個問題的講述在講解到遞迴時基本都將涉及。 所謂整數劃

整數劃分問題(python)--遞迴 and 動態規劃(m個盤裡放n個蘋果思想類似)

這篇部落格旨在對正整數劃分的多種題目就遞迴和動態規劃進行討論與總結 以下將正整數劃分分為三種題型:1.一般性,即對個數以及大小以及重複性不加約束 2.對重複性有約束 3.對元素的個數有約束。至於每個元

整數劃分總結(動態規劃

先引入一個比較實際的問題:分蘋果 題目 M個相同蘋果放到N個相同籃子裡有多少种放法,允許有籃子不放。 1<=M<=10,1<=N<=10 例如5個蘋果三個籃子,3,1,1 和 1,1,3是同一种放法 輸入 7 3 輸出 8 思路

OJ 7219 複雜的整數劃分問題__動態規劃

描述 將正整數n 表示成一系列正整數之和,n=n1+n2+…+nk, 其中n1>=n2>=…>=nk>=1 ,k>=1 。 正整數n 的這種表示稱為正整數n 的劃分。 輸入 標準的輸入包含若干組測試資料。每組測試資料是一

整數劃分問題---動態規劃、遞迴

第一: 將一個整數 n 劃分為 不超過m 組 的劃分數 如  n=4 m=3 輸出: 4 { 1+1+2=1+3=2+2=4} 思路:使用動態規劃: 定義狀態: dp[i][j] j的i劃分的組數 遞推:dp[i][j]=dp[i][j-i]+dp[i-1][j] ----

整數劃分動態規劃

經典問題。將正整數n表示成一系列正整數之和,n=n1+n2+..+nk  1. 將n劃分成不大於m的劃分法(多個整數可以相同) dp[n][m]= dp[n][m-1]+ dp[n-m][m]  dp[n][m]表示:整數 n 的劃分中,每個數不大於 m 的劃分數。

OJ 7215 簡單的整數劃分問題__動態規劃

描述 將正整數n 表示成一系列正整數之和,n=n1+n2+…+nk, 其中n1>=n2>=…>=nk>=1 ,k>=1 。 正整數n 的這種表示稱為正整數n 的劃分。正

整數劃分問題解法2-動態規劃

整數劃分 --- 一個老生長談的問題:  1) 練練組合數學能力.   2) 練練遞迴思想   3) 練練DP   總之是一道經典的不能再經典的題目:   這道好題求:   1. 將n劃分成若干正整數之和的劃分數。   2. 將n劃分成k個正整數之和的劃分數。   3. 將

HIT ~ 1402~整數劃分問題(動態規劃 or 母函式)

概念編輯所謂整數劃分,是指把一個正整數n寫成為其中,  為正整數,並且  ;  為n的一個劃分。如果  中的最大值不超過m,即  ,則稱它屬於n的一個m劃分。[1]求劃分個數編輯分析這裡我們記n的m劃分的個數為  。例如,當n=4時,有5個劃分,即  ,  ,  ,  ,  

動態規劃/揹包】整數劃分的5種情況

1.將n劃分成若干正整數之和的劃分數(可以存在相同整數)。 轉移方程如下: dp[n][m]=dp[n][m-1]+ dp[n-m][m]  dp[n][m]表示整數 n 的劃分中,每個數不大於 m

整數劃分問題 dp 動態規劃

原文:https://blog.csdn.net/u013377068/article/details/79765694#comments假設我們有一個整數n,我們要對它在約束條件不同的情況下進行劃分。1.把n劃分成不小於m(且為正整數)的劃分數2.把n劃分成為k個正整數的劃

動態規劃解決整數劃分的問題

前幾天去華為做機試,遇到一個整數劃分的問題,題目是:現有1,2,5,10,20,50,100 元這幾種錢幣,問給定n元能有多少種分配方式。例如n=4時,有1+1+1+1  ,1+2+1 , 2+2 三種劃分。我解決這道題是從網上看的方法,用的遞迴,但是悲劇的是測試用例執行超

OpenJudge簡單的整數劃分問題兩種方法(DFS)(動態規劃0ms),全域性題號7215,已AC

2:簡單的整數劃分問題 總時間限制: 100ms 記憶體限制: 65536kB描述 將正整數n 表示成一系列正整數之和,n=n1+n2+…+nk, 其中n1>=n2>=…>=n