第1部分 基礎算法(提高篇)--第3章 深搜的剪枝技巧-1440:【例題1】數的劃分

1440:【例題1】數的劃分

時間限制: 1000 ms 內存限制: 65536 KB
提交數: 1543 通過數: 1026
【題目描述】
將整數n分成k份,且每份不能爲空,任意兩份不能相同(不考慮順序)。

例如:n=7,k=3,下面三種分法被認爲是相同的。

{1,1,5};{1,5,1};{5,1,1};

問有多少種不同的分法。 輸出一個整數,即不同的分法。

【輸入】
兩個整數n,k(6<n≤200,2≤k≤6),中間用單個空格隔開。

【輸出】
一個整數,即不同的分法。

【輸入樣例】
7 3
【輸出樣例】
4
【提示】
四種分法爲:{1,1,5};{1,2,4};{1,3,3};{2,2,3}。


思路:將數字 n 劃分成 k 份,就是求 x1+x2+…+xk=n 方程的解,依次枚舉 x1到xk 的值,然後判斷。
剪枝分析
由於分解數不考慮順序,因此設定分解數依次遞增,所以擴展結點時的下個數應是不小於前一個擴展結點的值,即 a[i−1]≤a[i]
假設我們將 n 已經分解成了 a[1]+a[2]+…+a[i−1],則 a[i] 的最大值爲將 i~k 這 k-i+1 份平均劃分,即設 m=n−(a[1]+a[2]+…+a[i−1]),則 a[i]≤m/(k−i+1),所以擴展結點的上個數是 m/k−i+1.

#include<cstdio>
#include<iostream>
using namespace std;
int m,n,k,s;
int a[10];
void dfs(int k){
	if(n == 0) return;
	if(k == m)
	{
		if(n >= a[k-1])
		{
			s++;
			return;
		}
	}
	for(int i = a[k-1]; i <= n/(m-k+1);i++)//剪枝
	{
		a[k] = i;
		n -= i;
		dfs(k+1);
		 n += i; 
	}
} 
int main(){
	scanf("%d%d",&n,&m);
	a[0] = 1;
	dfs(1);
	printf("%d",s);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章