UVa12325 宝藏


前言

看到这个题目的第一眼就觉得应该用回溯法,思路就是从S1开始放,递归结束后再放S2,递归结束的条件是当背包的剩余空间小于min(min=S1<S2?S1:S2)时,判断这条解答树路径上的价值之和是不是比全局变量ans大,大则赋值给ans,否则结束递归。但是这会有一个问题,当背包的容量大而S1和S2特别小时,如背包tot容量位100,S1为1,S2为2时会要进行很多次递归,浪费了很多的时间和空间资源,那么有什么办法解决呢?


一、什么情况下算是背包容量大而S1,S2小?

当背包容量tot>S1S2时,在这种情况下方便下一步计算,因为当tot>S1S2时,可以计算出tot最多大于多少个S1S2,假设用循环得出n个满足条件,则在这nS1S2的容量里,既可以装S1个V1也可以装S2个V2,而nS1S2=nS1S2,则假设当V1>V2时,nS1S2V1>nS1S2V2,那么接下来可以用回溯法计算在背包容量为(tot-nS1*S2)时的最大价值,此时不会因为前言里的问题而导致时间空间浪费。

二、使用步骤

1.判断是否tot>S1*S2,如果是则求出n

这一步可用for循环求出,代码如下(示例):

if (s[0] * s[1] < tot)
  for (n = 1; n * s[0] * s[1] < tot; n++);
 //或者去掉if,n从0开始循环

2.在背包容量为(tot-nS1S2)的条件下回溯

整体代码如下(示例):

int tot, s[2], v[2], ans = -1, mins;

void dfs(int rest, int sum)
{
 if (rest < mins)
 {
  if (sum > ans)
   ans = sum;
  return;
 }
 for (int i = 0; i < 2; i++)
  if (rest >= s[i])
  
int main()
{
 int n = 0, ans1;
 scanf_s("%d", &tot);
 for (int i = 0; i < 2; i++)
  scanf_s("%d %d", &s[i], &v[i]);
 mins = s[0] < s[1] ? s[0] : s[1];
 if (s[0] * s[1] < tot)
  for (n = 1; n * s[0] * s[1] < tot; n++);
 tot -= n * s[0] * s[1];
 ans1 = n * (v[0] > v[1] ? v[0] : v[1]);
 dfs(tot, 0);
 printf("%d", ans + ans1);
 return 0;
}

总结

提示:因为网络原因没有在Uva上进行评测,只是在洛谷上试了一下样例并通过了,觉得这个想法很妙就先记录下来。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值