第一講,整數劃分 JAVA 程式碼(分治實現之一)
整數劃分問題相信很多人都做過,題意是這樣的:
將正整數n表示成一系列正整數之和,
n=n1+n2+,,,,,+nk(其中n1>=n2>=......>=nk>=1,k>1)
例如:正整數6有如下11種不同的劃分,
6=1+1+1+1+1+1
6=1+1+1+1+2
6=1+1+1+3
6=1+1+2+2
6=1+1+4
6=1+2+3
6=1+5
6=2+2+2
6=2+4
6=3+3
6=6
這道題網上搜一大把解題方法,什麼回溯法,動態規劃等等都可以解出來,昨晚突然想到一個新的解題思路(可能網上已經有人發表過了,不過確實是自己突然發現的,如有雷同,純屬巧合O(∩_∩)O~):
這道題的麻煩之處在於解題過程很容易產生重複的情況,不過只要按照下面的做法就不會出現重複的現象,
當對正整數N劃分,有如下劃分情況:
N=1+1+........+1
N=1+1+......+2
......
N=1+(N-1)
N=N
接下來如果對N+1(這裡用M代替N+1)進行劃分時,則在N劃分的所有情況前面都加1即
M=1+1+1+........+1
M=1+1+1+......+2
.......
M=1+N
加完之後對每一個新的表示式做如下操作:
步驟1.當表示式的個數小於等於2個時(如:3=1+2表示式的個數為2個),該表示式不作處理,判斷下一個表示式,否則執行步驟2
步驟2.當表示式的個數大於2個時,對錶達式的前兩個數字求和(如:5=1+2+3,則前兩個數即為1和2,),如果和小於等於第三個數字時,則構造新的表示式,即將當前表示式的前兩個數字合併,其他的保持一致:
如原來的表示式為:M=x1+x2+x3+....xn
則新的表示式為:M=(x1+x2) + x2+x3...+n
如果和大於第三個數字,如:7=2+2+3,前兩個數字的和為4,大於第三個數字。則不作處理,跳到步驟1,判斷下一個表示式
當全部的表示式(只包括前一個數字的表示式前面加1的那些表示式,不包括這個過程生成的新表示式)都執行完以上步驟之後,最終結果就只差一個了,即本身等於本身的情況,再加上該種情況即可
說的很不清楚,來點實際的吧:
如5的劃分情況為:
5=1+1+1+1+1
5=1+1+1+2
5=1+1+3
5=1+2+2
5=1+4
5=2+3
5=5
現在求6的劃分,則首先第一步,在5的每個表示式的前面都加1,則得到:
6=1+1+1+1+1+1
6=1+1+1+1+2
6=1+1+1+3
6=1+1+2+2
6=1+1+4
6=1+2+3
6=1+5
接著第二步,按順序對每個表示式執行之前說的步驟1和步驟2。
1.對於表示式:6=1+1+1+1+1+1,滿足步驟1,執行步驟2,因為前兩個數相加1+1=2大於第三個數1,所以不作處理,繼續判斷表示式2
2.對於表示式: 6=1+1+1+1+2,6=1+1+1+3 同樣不作處理,繼續下一個表示式
3.對於表示式: 6=1+1+2+2,前兩個求和:1+1=2等於第三個數,所以滿足條件,生成新的有效表示式:6=2+2+2,繼續下一個表示式
4.對於表示式: 6=1+1+4 , 6=1+2+3,同理,可以生成新的表示式:6=2+4,6=3+3
5.對於表示式: 6=1+5 不滿足步驟1中的條件
6.全部表示式遍歷完畢,結束,加上自身等於自身的情況,即:6=6
最終的結果就為:
6=1+1+1+1+1+1
6=1+1+1+1+2
6=1+1+1+3
6=1+1+2+2
6=1+1+4
6=1+2+3
6=1+5
6=2+2+2
6=2+4
6=3+3
6=6
終於寫完了,其實思路很簡單,但是要說清楚可真麻煩,根據這種思路,程式碼就可以寫了,不過程式碼也不是很好寫的,我這裡用了最簡單明瞭的程式碼完成以上功能,程式碼寫的很不上檔次,空間複雜度太高,有時間再優化,歡迎大牛拍磚!
[java]
import java.util.ArrayList;
import java.util.List;
public class IntegerSplit {
private List<int[]> result = new ArrayList<int[]>();
public void split(int m) {
//初始化
result.add(new int[]{1,1});
result.add(new int[]{2});
if (m == 1) {
System.out.println("1=1");
System.out.println("一共有:1種");
return ;
} else {
for (int i = 3; i <= m; i++) {
int size=result.size();
for(int j=0;j<size;j++){
int[] ca=result.get(j);
int[] newca=new int[ca.length+1];
newca[0]=1;
System.arraycopy(ca, 0, newca, 1, ca.length);
ca=null;
ca=newca;
result.set(j, ca);
int[] cs=merger(ca);
if(cs!=null){
result.add(cs.clone());
}
}
result.add(new int[]{i});
}
}
//列印結果
for(int[] ca:result){
System.out.print(m+"=");
for(int p=0;p<ca.length-1;p++){
System.out.print(ca[p]+"+");
}
System.out.print(ca[ca.length-1]);
System.out.println();
}
System.out.println("一共有:"+result.size()+"種");
}
//合併
public int[] merger(int[] ca) {
if (ca.length <= 2)
return null;
if (ca[0] + ca[1] <= ca[2]) {
int[] rca = new int[ca.length - 1];
rca[0] = ca[0] + ca[1] ;
System.arraycopy(ca, 2, rca, 1, ca.length - 2);
return rca;
}
return null;
}
public static void main(String[] args) {
new IntegerSplit().split(10);
}
}
import java.util.ArrayList;
import java.util.List;
public class IntegerSplit {
private List<int[]> result = new ArrayList<int[]>();
public void split(int m) {
//初始化
result.add(new int[]{1,1});
result.add(new int[]{2});
if (m == 1) {
System.out.println("1=1");
System.out.println("一共有:1種");
return ;
} else {
for (int i = 3; i <= m; i++) {
int size=result.size();
for(int j=0;j<size;j++){
int[] ca=result.get(j);
int[] newca=new int[ca.length+1];
newca[0]=1;
System.arraycopy(ca, 0, newca, 1, ca.length);
ca=null;
ca=newca;
result.set(j, ca);
int[] cs=merger(ca);
if(cs!=null){
result.add(cs.clone());
}
}
result.add(new int[]{i});
}
}
//列印結果
for(int[] ca:result){
System.out.print(m+"=");
for(int p=0;p<ca.length-1;p++){
System.out.print(ca[p]+"+");
}
System.out.print(ca[ca.length-1]);
System.out.println();
}
System.out.println("一共有:"+result.size()+"種");
}
//合併
public int[] merger(int[] ca) {
if (ca.length <= 2)
return null;
if (ca[0] + ca[1] <= ca[2]) {
int[] rca = new int[ca.length - 1];
rca[0] = ca[0] + ca[1] ;
System.arraycopy(ca, 2, rca, 1, ca.length - 2);
return rca;
}
return null;
}
public static void main(String[] args) {
new IntegerSplit().split(10);
}
}
輸出:
[java]
10=1+1+1+1+1+1+1+1+1+1
10=1+1+1+1+1+1+1+1+2
10=1+1+1+1+1+1+1+3
10=1+1+1+1+1+1+2+2
10=1+1+1+1+1+1+4
10=1+1+1+1+1+2+3
10=1+1+1+1+1+5
10=1+1+1+1+2+2+2
10=1+1+1+1+2+4
10=1+1+1+1+3+3
10=1+1+1+1+6
10=1+1+1+2+2+3
10=1+1+1+2+5
10=1+1+1+3+4
10=1+1+1+7
10=1+1+2+2+2+2
10=1+1+2+2+4
10=1+1+2+3+3
10=1+1+2+6
10=1+1+3+5
10=1+1+4+4
10=1+1+8
10=1+2+2+2+3
10=1+2+2+5
10=1+2+3+4
10=1+2+7
10=1+3+3+3
10=1+3+6
10=1+4+5
10=1+9
10=2+2+2+2+2
10=2+2+2+4
10=2+2+3+3
10=2+2+6
10=2+3+5
10=2+4+4
10=2+8
10=3+3+4
10=3+7
10=4+6
10=5+5
10=10
一共有:42種
10=1+1+1+1+1+1+1+1+1+1
10=1+1+1+1+1+1+1+1+2
10=1+1+1+1+1+1+1+3
10=1+1+1+1+1+1+2+2
10=1+1+1+1+1+1+4
10=1+1+1+1+1+2+3
10=1+1+1+1+1+5
10=1+1+1+1+2+2+2
10=1+1+1+1+2+4
10=1+1+1+1+3+3
10=1+1+1+1+6
10=1+1+1+2+2+3
10=1+1+1+2+5
10=1+1+1+3+4
10=1+1+1+7
10=1+1+2+2+2+2
10=1+1+2+2+4
10=1+1+2+3+3
10=1+1+2+6
10=1+1+3+5
10=1+1+4+4
10=1+1+8
10=1+2+2+2+3
10=1+2+2+5
10=1+2+3+4
10=1+2+7
10=1+3+3+3
10=1+3+6
10=1+4+5
10=1+9
10=2+2+2+2+2
10=2+2+2+4
10=2+2+3+3
10=2+2+6
10=2+3+5
10=2+4+4
10=2+8
10=3+3+4
10=3+7
10=4+6
10=5+5
10=10
一共有:42種
另外加多一段只求劃分總數,不求過程的程式碼:
[java]
public class ZSHF {
public static int q(int n,int m){
if(n<1||m<1)return 0;
if(n==1||m==1)return 1;
if(n<m)return q(n,n);
if(n==m)return q(n,m-1)+1;
return q(n,m-1)+q(n-m,m);
}
public static void main(String[] args) {
int number=10;
int result=q(number,number);
System.out.println("對整數"+number+"的劃分一共有:"+result+"種");
}
}
public class ZSHF {
public static int q(int n,int m){
if(n<1||m<1)return 0;
if(n==1||m==1)return 1;
if(n<m)return q(n,n);
if(n==m)return q(n,m-1)+1;
return q(n,m-1)+q(n-m,m);
}
public static void main(String[] args) {
int number=10;
int result=q(number,number);
System.out.println("對整數"+number+"的劃分一共有:"+result+"種");
}
}
輸出結果:
[java]
對整數10的劃分一共有:42種