以下這兩個題目代表了遞推當中的兩種基本思路,即遞歸和遞推。
P1928
分析:這是一個分層的問題,這或許告訴我們層數適量的括號匹配可以通過遞歸來做,可以大大簡化思考量。
一份好代碼:
由於遞歸使用棧,不需要其他的數據結構來存儲分層的信息,所以(?)空間複雜度更低。減少了一次性輸入的時間耗費但每次讀入一個字符還是很浪費時間的。
#include<iostream>
using namespace std;
string work()
{
string ret="";//記錄答案
char ch;
while(cin>>ch)//一直讀入
{
if(ch=='[')//如果是[
{
int x;
cin>>x;//讀入複製次數
string t=work();//遞歸要賦值的串
for(int j=1;j<=x;j++)//循環複製
ret+=t;//複製一遍
}
else if(ch==']')//如果是]
return ret;//返回答案
else//否則是字符
ret+=ch;//累加到答案中
}
return ret;//返回答案
}
int main()
{
cout<<work()<<endl;//輸出答案
return 0;//程序結束
}
P1164
這個題目是一個很好的揹包入門題目,主要掌握兩個思路,一個是基礎的填表,另一個是通過逆序求和來降維。
填表是揹包問題的基礎思路,即多少錢能買多少東西的一張表。複雜度爲。雖然對於揹包來說,時間複雜度不能再降低了。但是空間可以通過降維方法得到很好的解決。我們可以這樣思考:
一組數求和可以使用先儲存再遍歷的手段。
s[i] = s[i-1] + a[i];
但我們發現這樣的話,保存了很多沒有必要的中間結果,即s[0]
到s[n-2]
所以,如果只需要最末尾的那個和,可以將和值用一個變量進行迭代:
s += a[i];
至於dp表,其實也是這個道理,中間很大的部分都沒有被最終利用到,所以我們將中間的那麼多行全部省掉。在這個題目中,我們省去了99%的內存。
大佬代碼如下
#include <iostream>
using namespace std;
int n, m, a[110], f[10010] = {1};
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= n; i++)
for (int j = m; j >= a[i]; j--)
f[j] += f[j-a[i]];
cout << f[m];
return 0;
}