PTA7-37 整數分解為若干項之和(20 分)超級詳解
阿新 • • 發佈:2018-12-24
將一個正整數N分解成幾個正整數相加,可以有多種分解方法,例如7=6+1,7=5+2,7=5+1+1,…。程式設計求出正整數N的所有整數分解式子。
輸入格式:
每個輸入包含一個測試用例,即正整數N (0<N≤30)。
輸出格式:
按遞增順序輸出N的所有整數分解式子。遞增順序是指:對於兩個分解序列N1={n1,n2,⋯}和N2={m1,m2,⋯},若存在i使得n1=m1,⋯,ni=mi,但是ni+1<mi+1,則N1序列必定在N2序列之前輸出。每個式子由小到大相加,式子間用分號隔開,且每輸出4個式子後換行。
輸入樣例:
7
輸出樣例:
7=1+1+1+1+1+1+1;7=1+1+1+1+1+2;7=1+1+1+1+3;7=1+1+1+2+2
7=1+1+1+4;7=1+1+2+3;7=1+1+5;7=1+2+2+2
7=1+2+4;7=1+3+3;7=1+6;7=2+2+3
7=2+5;7=3+4;7=7
此題是深度優先搜尋演算法的變形,除去了訪問標誌。我們先來回顧下什麼是深度優先搜尋,以此題為背景,以N=3為例,則從1開始一直搜尋,搜尋到1 1,再搜尋1,即狀態為1 1 1,發現滿足要求,返回上一層,狀態變成1 1,再搜尋2,即狀態變為1 1 2,發現當前和超過3,返回上一層,狀態變為1 1 ,再搜尋3,以此類推,直到搜尋到N=3,返回上一層變為1 1,因為搜尋N個搜尋完了,再返回上一層狀態變為1。至此,1 1開頭,後一位為試探數已經試探完畢,故1 2開頭,搜尋,直到N=3,1,3開頭。。。最後返回到1,1變為2,以2開頭。。。依次類推,其本質為對N做一個全排列,總數為N! 這就是所謂的試探回溯法,先逐層試探,滿足條件了再逐層回溯。以下提供完整AC程式碼並有詳細註釋:
#include<iostream> using namespace std; int sum=0,pos=-1,countN=0,N;//定義試探和,試探陣列指標,試探成功次數計數器,待匹配數 int Result[31];//定義試探陣列,存放試探數字 void DFS(int x)//深度優先搜尋,層層遞迴,逐一試探 { if(sum==N)//如果試探和等於待匹配數 { countN++;//成功次數+1 cout<<N<<'='; for(int i=0;i<pos;i++)//輸出試探數 cout<<Result[i]<<'+'; if(countN%4==0||Result[pos]==N)//判定最後一個試探數的情況 //如果成功次數為4的倍數或者試探數等於待匹配數 cout<<Result[pos]<<'\n';//輸出試探數並換行 else cout<<Result[pos]<<';';//否則按格式輸出 return; } else if(sum>N)//如果試探和大於待匹配數,則返回到上一層 return; for(int i=x;i<=N;i++)//範圍從輸入引數,即上一層傳進來的試探數開始到待匹配數 { Result[++pos]=i;//指標指向下一位置並儲存當前變數為試探數 sum+=i;//試探和累加試探數 DFS(i);//遞迴試探 sum-=i;//試探完畢後減去試探數,以待下一迴圈加上新的試探數來試探 pos--;//指標回覆到原來的位置,以待下一次自增並儲存新的試探數 }//注意,sum,pos作為全域性變數,在連續遞迴呼叫的情況下會一直自增,故無需擔心自增後馬上被減去 } int main() { cin>>N; DFS(1); return 0; }