廢話不多說,直接看題。
首先先來說明一下題意:具體就是說一共要分成k個數,它們的和為n,看到這你們會想到什么,小編第一眼就會想到小學/學前班學的東西,把一個數拆成兩個數的和。如:
就像這樣,只是情況有變,把一個數分成更多的數的和就OK了。
行了,扯的遠了,回歸正題,既然這道題出現在搜索中,就用搜索吧(其實其它方法也可以,隔壁Willian用三重循環強行打過)。
既然搜索,就先考慮一下用深搜還是廣搜,就用深搜把(個人偏愛),那怎么搜呢?舉個栗子以題目的栗子為栗,7怎么分?為了按順序,那么第一位先取1吧,接下來我們還有6要分,還剩下兩個數;第二位也取1吧,那么我們還有5要分,還剩下1個數的位置,於是我們就會發現還剩下一個數的位置,只能放5了,那么就方案數加1,返回。
這樣整個搜索程序不就豁然開朗了嗎?放進去三個參數,分別是上一個數的值,剩余要分的數的個數與剩下要分的數值。
此時我想你一定會有一個大大的問號吧,為什么要傳上一個數的值呢?因為按照之前的栗子,為了按順序來,是不是后面的數總會保持比前一個數大或者相等,這一點很容易理解,如果比之前的數小了,會出現重復(如1,1,5和5,1,1重復)的情況,正是如此,我們所要每一次填進去的數的范圍也會得到減小,抽象的來說就是這樣:前一個數<=本次所填的數<剩下要分的數值/數的個數(這是最不好理解的地方,此處的限制是為了防止前面的數過大,而后面的數連1都不能取,這樣可以有效的避免了這種情況,所以在邊界條件處不需要再進行判斷還能不能取,因為后面的數都會滿足這個關系式,所以后面的數最小都可以等於這個所填的數,所以剩下要分的數值/數的個數能保證后面的數大於或等於這個所填數),這樣程序就寫出來了(代碼比較簡單且上文有解釋,就不寫注釋了,原諒小編的手懶):
1 #include<iostream> 2 using namespace std; 3 int n,k,a[10000],sum=0,ans; 4 void dfs(int past,int cnt,int num) 5 { 6 if(cnt==1) 7 { 8 ans++; 9 return; 10 } 11 for(int i=past;i<=num/cnt;i++) 12 dfs(i,cnt-1,num-i); 13 } 14 int main() 15 { 16 cin>>n>>k; 17 dfs(1,k,n); 18 cout<<ans; 19 return 0; 20 }