1. 程式人生 > >PTA7-37 整數分解為若干項之和(20 分)超級詳解

PTA7-37 整數分解為若干項之和(20 分)超級詳解

將一個正整數N分解成幾個正整數相加,可以有多種分解方法,例如7=6+1,7=5+2,7=5+1+1,…。程式設計求出正整數N的所有整數分解式子。

輸入格式:

每個輸入包含一個測試用例,即正整數N (0<N30)。

輸出格式:

按遞增順序輸出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;
}