DFS+剪枝:N个蛋放入M个篮子并可以任意取

淘宝笔试题:

     有N个蛋和M个篮子,把蛋放到M个篮子里,每个篮子都不能为空。另外,需要满足:任意一个小于N的正整数,都能由某几个篮子内蛋的数量相加的和得到。写出程序,使得输入一个(N,M),输出所有可能的分配情况

 

#include "StdAfx.h"
#include <iostream>
#include <math.h>
using namespace std;
#define MAX 1000
int ans[MAX];
int count = 0;
int cal = 0;
//如果前x的篮子已经放了y个鸡蛋,则第x+1个篮子可以放1到y+1个鸡蛋,(如果放y+2,则取不出y+1)
//第x+2个篮子可以放(y+y+1)+1=2y+2
//第x+3个篮子可以放(2y+2+y+1+y)+1=4y+4,这样我们可以从0开始 ,依次开始遍历所有存放情况
void dfs(int hasEgg,int nextBasketIndex,int totalEgg,int totalBasket,int last){

	

	if(hasEgg==totalEgg && nextBasketIndex==totalBasket){


		for(int i=0;i<totalBasket;i++){

			printf("%d ",ans[i]);
			
		}
		printf("\n");
		count++;
		return ;
	}
	if(nextBasketIndex>=totalBasket||hasEgg>=totalEgg){
					
				return;
	}
	//剪枝1:如果后面的所有篮子都用最小数来填充 都比总数大
	if(hasEgg+last*(totalBasket-nextBasketIndex)>totalEgg)return;
	//剪枝2:如果后面的所有篮子都用最大数来填充 还是不够大
	if((hasEgg+1)*(pow(2,totalBasket-nextBasketIndex)-1)+hasEgg<totalEgg)return;
	for(int i=last;i<=hasEgg+1;i++){

		ans[nextBasketIndex] = i;
		cal++;
		
		dfs(hasEgg+i,nextBasketIndex+1,totalEgg,totalBasket,i);
	}

}
int solve(int egg,int basket){

	if(egg>pow(2,basket)||basket>egg)
		return 0;
	dfs(0,0,egg,basket,1);
	return count;
	
}
void main(){

	solve(16,10);
	printf("结果:%d\n运算次数:%d\n",count,cal);
}
posted on 2011-09-01 17:15  yangyh  阅读(531)  评论(0编辑  收藏  举报