gpt4 book ai didi

c++ - 背包问题变体的递归关系?

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:02:47 25 4
gpt4 key购买 nike

我发现很难理解在 codeforces 上解决这个问题的两个具体实现 link .

我理解这类似于背包问题。但是,当我自己解决它时,我并不知道该算法。我是根据自己对动态规划的理解解决的。我的想法是把色带剩余的长度作为下一个状态。这是我的代码

#include<iostream>

using namespace std;


int main(){
int n,res1=0,res2,x=0;
int a,b,c;
cin >> n >> a >> b >> c;
for(int i=0;i <= n/a; i++){
res2 = -20000;
for(int j=0; j <= (n-(a*i))/b; j++){
x = (n - (a*i) - (b*j));
res2=max(res2,(j + ((x % c) ? -10000 : x/c)));
}
res1=max(res1,i+res2);
}
cout << res1 << endl;
return 0;

实现 1:

  1 #include <bits/stdc++.h>
2 using namespace std;
3 int main()
4 {
5 int f[4005],n,a,i,j;
6 fill(f+1,f+4005,-1e9);
7 cin>>n;
8 for(;cin>>a;)
9 for(i=a;i<=n;i++)
10 f[i]=max(f[i],f[i-a]+1);
11 cout<<f[n];
12 }

实现 2:

  1 #include <bits/stdc++.h>
2 int n, a, b, c, ost;
3 std::bitset<4007> mog;
4 main()
5 {
6 std::cin>>n>>a>>b>>c;
7 mog[0]=1;
8 for (int i=1; i<=n; i++)
9 if ((mog=((mog<<a)|(mog<<b)|(mog<<c)))[n])
10 ost=i;
11 std::cout << ost;
12 }

虽然我理解解决背包问题的一般思路。我不清楚实现 1 中的第 8、9、10 行是如何实现这一点的。具体而言,无论 a、b、c 的输入值如何,内部 for 循环都是针对接收到的相应值 a 遍历数组。

同样,我可以看到实现 2 中的第 8、9、10 行做了同样的事情。但是我完全不知道这段代码是如何工作的。

请帮助我理解这一点。我觉得这两个解决方案有一些我没有看到的隐藏结构。提前致谢。

最佳答案

实现1

这是非常简单的动态规划实现。

外层循环只遍历三个值:abc

  8         for(;cin>>a;)

内部循环访问数组的每个元素并更新给定色带长度的当前已知最佳切割数。

  9                 for(i=a;i<=n;i++)
10 f[i]=max(f[i],f[i-a]+1);

实现2

我不认为它可以称为动态规划,但技巧很巧妙。

它分配长度等于最大n 的位数组。然后在左边设置一位。这意味着,长度为 0 的色带是有效的解决方案。在每次迭代中,算法将给定数组向左移动 abc。每个这样的转变的结果都可以看作是色带的新有效尺寸。通过 or 所有 3 个移位的结果,我们在第 i 次切割后得到所有有效尺寸。如果设置了 n 位,我们知道大小为 n 的色带可以被切割 i 次而没有剩余。

n = 10
a = 2
b = 3
c = 5

i=1:
0|0000000001 // mog
0|0000000100 // mog<<a
0|0000001000 // mog<<b
0|0000100000 // mog<<c
0|0000101100 // mog=(mog<<a)|(mog<<b)|(mog<<c)
^ here is a bit checked in 'if' statement '(mog=(...))[n]'
i=2:
0|0000101100 // mog
0|0010110000 // mog<<a
0|0101100000 // mog<<b
1|0110000000 // mog<<c // here we have solution with two pieces of size 5
1|0111110000 // (mog<<a)|(mog<<b)|(mog<<c)
^ now bit set, so we have a solution

我们知道在那一点上恰好有 i 次切割,所以我们设置 ost=i。但是我们找到了最坏的解决方案,我们必须继续前进,直到我们确定没有更多的解决方案。

最终我们会达到这样的状态:

i=5:
1|1100000000 // mog
1|0000000000 // mog<<a // 5 pieces of size 2
0|0000000000 // mog<<b
0|0000000000 // mog<<c
1|0000000000 // (mog<<a)|(mog<<b)|(mog<<c)

这是最后一次设置位置 n 的位。所以我们将设置 ost=5 并进行更多迭代。

算法使用 n 作为可能切割的上限,但很明显这个界限可以改进。例如 n/min({a,b,c}) 就足够了。

关于c++ - 背包问题变体的递归关系?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56460293/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com