P1441 砝码称重
Posted garen-wang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1441 砝码称重相关的知识,希望对你有一定的参考价值。
dfs+小剪枝+背包方案数的一道题
这道题有一个前置技能:你要会求那(n-m)个砝码能表示多少的重量。
因为在这道题里面每个砝码只能取一次,所以相当于一个少了一个属性的01背包方案数。套上相应内容即可求解。
这应该也能有所帮助:https://www.cnblogs.com/Garen-Wang/p/9800949.html
然后就能看这道题了。
前面的东西都不用过脑子就知道是dfs。
所以可以像普通的dfs那样去掉(m)个然后套上上面的01背包方案数去求解。
但是dfs过程就有点慢了,T了好几个点。
所以附上一个剪枝:
去掉(m)个砝码这个操作是无序的,而如果你认为是有序的话你就会多枚举出了好几次相同的组合。
解决方法:记录上次取的砝码的下标是哪个,然后下一层dfs就从下一位开始。
这个东西确实挺重要的,积累下来吧。
所以就能过了。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
const int maxn = 21;
int a[maxn];
bool vis[maxn];
int weight[maxn];
int dp[2005];
int n, m;
int ans = -0x3f3f3f3f;
void dfs(int t, int pos)
{
if(t == m + 1)
{
memset(dp, 0, sizeof dp);
dp[0] = 1;
int len = 0;
for(int i = 1; i <= n; i++) if(!vis[i]) weight[++len] = a[i];
for(int i = 1; i <= len; i++)
{
for(int j = 2000; j >= weight[i]; j--)
{
dp[j] += dp[j - weight[i]];
}
}
int res = 0;
for(int i = 1; i <= 2000; i++) if(dp[i]) res++;
ans = std::max(ans, res);
}
else
{
for(int i = pos; i <= n; i++)
{
if(!vis[i])
{
vis[i] = true;
dfs(t + 1, i + 1);
vis[i] = false;
}
}
}
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
}
dfs(1, 1);
printf("%d
", ans);
return 0;
}
以上是关于P1441 砝码称重的主要内容,如果未能解决你的问题,请参考以下文章