剪枝求调(有注释)
查看原帖
剪枝求调(有注释)
482452
Bamboo_Day楼主2023/3/8 22:26

我的思路是用a记录菜的价格,b相当于一个桶记录价格为i的菜有几种

dfs每一种价格,往下搜索当前价格取i个的方案数,再乘上当前价格的菜品数量中取出i个菜的方案数,并往前递归

#include <iostream>
using namespace std;
inline int read(){//快速读入 
	int x=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9'){
		if(c=='-')f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		x=(x<<1)+(x<<3)+(c^48);
		c=getchar();
	} 
	return x*f;
}
int n,m, a[200],b[1005],cnt = 0;//a表示存在的菜品价格,b表示该价格有多少种菜品,b相当于一个桶
inline long long C(int n, int m){//组合数C
	if(m == 0) return 0;
	if(n == m) return 1;
	long long ans = 1;
	if(n - m > m){
		for(int i = n-m+1; i <= n; i++){
			ans *= i;
		}
		for(int i = 2; i <= m; i++){
			ans /= i;
		}
	}else{
		for(int i = m+1; i <= n; i++){
			ans *= i;
		}
		for(int i = 2; i <= n-m; i++){
			ans /= i;
		}
	}
	return ans;
}

inline int dfs(int step, int ans){//step表示当前进行到第几种价格的菜品,ans表示已经选了多少圆的菜
	int sum = 0;//从当前函数开始算一共有多少种取法
	if(step == cnt+1){
		if(ans == m) return 1;
		return 0;
	}
	if(ans > m){
		return 0;
	}
	for(int i = 0; i <= b[a[step]]; i++){
		if(dfs(step+1,ans + a[step] * i)){//当前价格的菜品取i种
			sum += C(b[a[step]],i) * dfs(step+1,ans + a[step] * i);//乘法原理
		}
	}
	return sum;
}
int main(){
	n = read(),m = read();
	while(n--){//读入并去重
		cin >> a[++cnt];
		b[a[cnt]]++;
		if(b[a[cnt]]!=1){
			cnt--;
		}
	}
	cout << dfs(1,0)<< endl;
	return 0;
}
2023/3/8 22:26
加载中...