我发现很难理解在代码部队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行执行相同的操作。但是我完全不知道这段代码是如何工作的。
请帮助我理解这一点。我觉得这两个解决方案有些隐藏的结构,我看不到。预先感谢。
答案 0 :(得分:1)
这是动态编程的非常简单的实现。
外循环仅经历三个值:a
,b
和c
8 for(;cin>>a;)
内部循环访问数组的每个元素,并在给定的碳带长度上更新当前最知名的切割数量。
9 for(i=a;i<=n;i++)
10 f[i]=max(f[i],f[i-a]+1);
我不认为它可以称为动态编程,但是窍门很整洁。
它分配长度等于最大n
的位数组。然后在左侧设置一位。这意味着长度为0的功能区是有效的解决方案。
在每次迭代中,算法将给定的数组向左移动a
,b
和c
。每次移位的结果都可以视为色带的新有效尺寸。通过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})
就足够了。