整數劃分問題是把一個正整數 N 拆分成一組數,并且使這組數相加等于 N 的問題.
比如:
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
這里,5+1和1+5是同一種分法。
這里探討整數劃分的可行解的數目。
問題求解:
首先假設正整數n拆分成k個數(不允許有0),用f(n,k)表示正整數n拆分成k個數的可行拆分種類的數目。
那么
f(n,n)表示n拆分成n個數(即只有n個1),顯然f(n,n) = 1
然后,可以按照這k份中是否有一份的數為1分成兩類:
1) 這k份中沒有1份含1的:那么可以在n中拿出k個"1"出來,分到k份中,再將剩下n-k分到k份中,于是這時有
f(n,k) = f(n-k,k)
2) 這k份中至少有一份含有1:首先在n中拿1個"1"出來,再將剩下n-1分到k-1份中,于是這時有:f(n,k) = f(n-1,k-1)
綜合起來就是:
f(n,n) = 1
f(n,k) = f(n-k,k) + f(n-1,k-1)
這兩個遞歸式可以使用動態規劃求解。
題目鏈接:
http://poj.org/problem?id=1283題解:直接按照整數劃分來解
代碼:
import java.util.Scanner;
import java.util.Arrays;;

public class Main


{
private static long [][]dp = new long[205][205];
private static long Test(int _n,int _k)

{
if(_n < _k)
return 0;
for(int i = 0; i <= _n; ++i)
Arrays.fill(dp[i],0);
for(int i = 1; i <= _n; ++i)

{
dp[i][i] = 1;
}
for(int i = 2; i <= _n; ++i)

{
for(int j = 1; j <= _k; ++j)

{
dp[i][j] = dp[i-1][j-1];
if(i - j > 0)
dp[i][j] += dp[i-j][j];
}
}
return dp[_n][_k];
}
public static void main(String[] args)

{
int n,k;
Scanner in = new Scanner(System.in);
n = in.nextInt();
k = in.nextInt();
while(!(n == 0 && k == 0))

{
System.out.println(Test(n,k));
n = in.nextInt();
k = in.nextInt();
}

}

}


代碼:
import java.util.Scanner;
import java.util.Arrays;

public class Main


{
private static long [][]dp = new long[32][32];
private static long Test(int _n,int _k)

{
if(_n < _k)
return 0;
for(int i = 0; i <= _n; ++i)
Arrays.fill(dp[i],0);
for(int i = 1; i <= _n; ++i)

{
dp[i][i] = 1;
}
for(int i = 2; i <= _n; ++i)

{
for(int j = 1; j <= _k; ++j)

{
dp[i][j] = dp[i-1][j-1];
if(i - j > 0)
dp[i][j] += dp[i-j][j];
}
}
return dp[_n][_k];
}
public static void main(String[] args)

{
Scanner in = new Scanner(System.in);
int testcase = in.nextInt();
int m,n;
for(int i =0; i < testcase; ++i)

{
m = in.nextInt();
n = in.nextInt();
System.out.println(Test(m+n,n));
}
}
}


posted on 2011-03-28 18:42
bennycen 閱讀(1171)
評論(1) 編輯 收藏 引用