线性动态规划刷题
洛谷P3637最长上升子序列时间复杂度O(n^2)
#include<iostream>
#include<algorithm>
using namespace std;
const int N=50005;
int a[N],f[N];
int main(){
int n;cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++){
f[i]=1;
for(int j=1;j<i;j++){
if(a[j]<a[i]){
f[i]=max(f[i],f[j]+1);
}
}
}
int res=0;
for(int i=1;i<=n;i++)res=max(res,f[i]);
cout<<res<<endl;
return 0;
}
可以进行二分优化时间复杂度O(nlogn)
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=5005;
int a[N];
int q[N];
int n;
int main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
int len=0;
for(int i=1;i<=n;i++){
int l=0,r=len;
while(l<r){
int mid=l+r+1>>1;
if(q[mid]<a[i])l=mid;
else r=mid-1;
}
len=max(len,r+1);
q[r+1]=a[i];
}
cout<<len<<endl;
return 0;
}
洛谷P2758编辑距离 时间复杂度O(la*lb)
定义char数组cin a和b strlen求长度
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2005;
char a[N],b[N];
int f[N][N];
int main(){
cin>>a+1>>b+1;
int la=strlen(a+1),lb=strlen(b+1);
for(int i=1;i<=la;i++)f[i][0]=i;
for(int i=1;i<=lb;i++)f[0][i]=i;
for(int i=1;i<=la;i++){
for(int j=1;j<=lb;j++){
f[i][j]=min(f[i-1][j]+1,f[i][j-1]+1);
if(a[i]==b[j])f[i][j]=min(f[i][j],f[i-1][j-1]);
else f[i][j]=min(f[i][j],f[i-1][j-1]+1);
}
}
cout<<f[la][lb]<<endl;
return 0;
}
洛谷P1439最长公共子序列 动态规划时间复杂度O(n^2)
#include<iostream>
using namespace std;
int n,m;
const int N=1010;
char a[N],b[N];
int f[N][N];
int main(){
cin>>n>>m>>a+1>>b+1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
f[i][j]=max(f[i-1][j],f[i][j-1]);
if(a[i]==b[j])f[i][j]=max(f[i][j],f[i-1][j-1]+1);
}
}
cout<<f[n][m]<<endl;
return 0;
}
进行二分优化,通过map映射a然后通过b加入f,f为每次记录最后一个位置的单调数组,然后进行a映射的位置的插入,不满足b对a时二分找到位置修改为最优。
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100010;
int a[N],b[N],map[N],f[N];
int n;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
map[a[i]]=i;
}
for(int i=1;i<=n;i++){
cin>>b[i];
f[i]=0x7fffffff;
}
int len=0;
f[0]=0;
for(int i=1;i<=n;i++){
int l=0,r=len;
if(map[b[i]]>f[len])f[++len]=map[b[i]];
while(l<=r){
int mid=l+r>>1;
if(f[mid]>map[b[i]])r=mid-1;
else l=mid+1;
}
f[l]=min(f[l],map[b[i]]);
}
cout<<len<<endl;
return 0;
}
洛谷P1999导弹拦截
求最大不上升子序列和最大上升子序列
#include<iostream>
#include<cstring>
using namespace std;
const int N=100010;
int a[N],q[N];
int main(){
int n=1;
int x;
while(cin>>a[n]){
n++;
}
n--;
int len=0;
for(int i=1;i<=n;i++){
int l=0,r=len;
while(l<r){
int mid=l+r+1>>1;
if(q[mid]>=a[i])l=mid;
else r=mid-1;
}
len=max(len,r+1);
q[r+1]=a[i];
}
cout<<len<<endl;
len = 0;
memset(q,0,sizeof(q));
for(int i=1;i<=n;i++){
int l=0,r=len;
while(l<r){
int mid=l+r+1>>1;
if(q[mid]<a[i])l=mid;
else r=mid-1;
}
len=max(len,r+1);
q[r+1]=a[i];
}
cout<<len<<endl;
return 0;
}
洛谷P2285打鼹鼠
通过结构体记录xy和对应的时间,然后找状态枚举终点i从j走到i进行找状态f[i]的最大值,f[i]为以i结尾我们最多能抓到多少鼹鼠。
#include<iostream>
#include<cmath>
using namespace std;
const int M=10010;
int n,m;
struct node{
int t,x,y;
}node[M];
int f[M];
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>node[i].t>>node[i].x>>node[i].y;
}
for(int i=1;i<=m;i++){
f[i]=1;
for(int j=1;j<i;j++){
if((abs(node[i].x-node[j].x)+abs(node[i].y-node[j].y))<=node[i].t-node[j].t){
f[i]=max(f[i],f[j]+1);
}
}
}
int res=0;
for(int i=1;i<=m;i++)res=max(res,f[i]);
cout<<res<<endl;
return 0;
}