今天看了《挑战程序设计竞赛》的动态规划部分,感觉对以前一些知其然却不知其所以然的问题有了更好的理解,先整理一部分。
题意:
有一个长为n的数列
分析:
设
dp[i] = max(dp[i], dp[j] + 1) (a[i] > a[j])
代码:
#include<iostream>
using namespace std;
int a[105], dp[105];
int main (void)
{
int n, ans = 0; cin>>n;
for (int i = 0; i < n; i++) cin>>a[i];
fill(dp, dp + n, 1);
for (int i = 0; i < n; i++){
for (int j = 0; j < i; j++){
if(a[i]>a[j])
dp[i] = max (dp[i], dp[j] + 1);
}
ans = max (dp[i], ans);
}
cout<<ans<<endl;
return 0;
}
分析:
还可以定义
dp[i] = min(dp[i], a[j]) (a[j]>dp[i-1]||i==1)
代码:
#include<iostream>
using namespace std;
const int INF=0x3fffffff;
int a[105], dp[105];
int main (void)
{
int n, ans = 0; cin>>n;
for (int i = 0; i < n; i++) cin>>a[i];
fill(dp + 1, dp + n + 1, INF);
dp[0] = a[0];
for(int j = 0; j < n; j++){
for(int i = 1; i <= n; i++){
if(i == 1||a[j] > dp[i-1])
dp[i] = min(dp[i], a[j]);
}
}
for(int i = n; i >= 1; i--){
if(dp[i] != INF){
cout<<i<<endl;
break;
}
}
return 0;
}
分析:
上述方法中
代码:
#include<iostream>
using namespace std;
const int INF=0x3fffffff;
int a[105], dp[105];
int _binary_search(int l, int r, int num)
{
while(l < r){ //区间[l,r)
int mid = l + (r - l)/2;
if(dp[mid] >= num) r = mid;
else l = mid + 1;
}
return l;
}//获取下界
int main (void)
{
int n, ans = 0; cin>>n;
for (int i = 0; i < n; i++) cin>>a[i];
fill(dp + 1, dp + n + 1, INF);
for(int j= 1; j <= n; j++){
int pos = _binary_search(1, n+1, a[j]);
dp[pos] = a[j];
}
for(int i = n; i >= 1; i--){
if(dp[i] != INF){
cout<<i<<endl;
break;
}
}
return 0;
}
分析:
可以直接使用STL中的lower_bound获取下界。通过dp数组中INF的下界获取上升子序列长度。为方便表示可直接定义
代码:
#include<iostream>
using namespace std;
const int INF=0x3fffffff;
int a[105], dp[105];
int main (void)
{
int n, ans = 0; cin>>n;
fill(dp, dp + n, INF);
for (int i = 0; i < n; i++){
cin>>a[i];
*lower_bound(dp, dp + n, a[i]) = a[i];
}
cout<<lower_bound(dp, dp +n, INF) - dp<<endl;
return 0;
}