luogu1441砝码称重(深搜+背包:组合数+01背包)

25 篇文章 0 订阅
8 篇文章 0 订阅

题目连接

#同类的题目还有这些#

题目大意:

    n个砝码选其中m个,求他们能组合出来的重量最多。

解题思路(简单粗暴):

    1 n个砝码选m个,吃果果的组合数,dfs搞起来

    2 问m个砝码能组合出来的重量:01背包。

游戏结束(PS:深搜的参数意义,一定要搞懂,我WA了3次):

#include<cstdio>
#include<cstring>

int n,m,b[110],a[110],f[20010],mx=0,ans=0;

void dp()
{
	memset(f,-1,sizeof(f));f[0]=1;
	int	su=0;
	for(int i=1;i<=n;i++)
	{
		if(b[i]==0) continue;
		int t=a[i];
		for(int j=mx;j>=t;j--)
		{
			if(f[j-t]==1&&f[j]==-1)//第一次出现的格子,记录次数 
			{
				su++;f[j]=1;
			}
		}	
	}
	if(ans<su) ans=su;
} 

void dfs(int x,int k) //当前是 x 个,选了 k 个
{
	if(k==m)//选够了,去跑01背包 
	{
		dp(); return ;
	}
	if(x>n) return ;
	dfs(x+1,k);//不选当前点,直接去下一层
	
	b[x]=1;//选当前点 
	dfs(x+1,k+1);
	b[x]=0; 
} 


int main()
{
	scanf("%d %d",&n,&m); m=n-m;
	memset(b,0,sizeof(b));
	
	for(int i=1;i<=n;i++) { scanf("%d",&a[i]); mx+=a[i]; }
	
	dfs(1,0);
	
	printf("%d",ans);
	 
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是一道经典的组合数学题目,需要用到组合数的性质。 我们可以先考虑 $n=5$ 的情况。这时,一共有 $2^n=32$ 种可能的抛硬币的结果,其中正面朝上的硬币数为 $0,1,2,3,4,5$ 的情况分别有 $1,5,10,10,5,1$ 种。 接下来,我们考虑 $n$ 的任意情况。可以证明,当 $n$ 为偶数时,正面朝上的硬币数的种数与 $n=5$ 时是相同的;当 $n$ 为奇数时,正面朝上的硬币数的种数比 $n=5$ 时多一种。这是因为当抛硬币的次数为偶数时,正反面的数量是相等的,因此正面朝上的硬币数的种数与 $n=5$ 时相同;当抛硬币的次数为奇数时,正反面的数量不相等,因此正面朝上的硬币数的种数比 $n=5$ 时多一种。 因此,需要分别处理 $n$ 为奇数和偶数的情况。当 $n$ 为偶数时,正面朝上的硬币数的种数与 $n=5$ 时相同,因此答案为: $$ \sum_{i=0}^{n/2} \binom{n}{i} $$ 当 $n$ 为奇数时,正面朝上的硬币数的种数比 $n=5$ 时多一种,因此答案为: $$ \sum_{i=0}^{n/2} \binom{n}{i} + \sum_{i=0}^{n/2} \binom{n}{i+1} $$ 需要注意的是,当 $n$ 为 $0$ 时,只有一种可能的结果,即所有硬币都是反面朝上,因此答案为 $1$。 以下是一份参考代码,可以用于计算答案: ```c++ #include <iostream> #include <cmath> using namespace std; int main() { int n; cin >> n; if (n == 0) { cout << "1" << endl; } else { int ans = pow(2, n); if (n % 2 == 0) { for (int i = 0; i <= n / 2; i++) { ans -= 2 * pow(-1, i) * pow(2, n - i) * (1 << i) / (i + 1); } } else { for (int i = 0; i <= n / 2; i++) { ans -= 2 * pow(-1, i) * pow(2, n - i) * (1 << i) / (i + 1); } for (int i = 0; i <= n / 2; i++) { ans -= 2 * pow(-1, i) * pow(2, n - i - 1) * (1 << i) / (i + 1); } } cout << ans << endl; } return 0; } ``` 代码中使用了数学公式计算答案,其中 $\binom{n}{i}$ 使用了移项后再计算的方式,避免了复杂的组合数计算。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值