模板庫(四) - 動態規劃演算法模板
阿新 • • 發佈:2019-01-07
寫在前面
“模板庫”這一系列文章用來複習
模板
由於時間原因,作者無法一一親自除錯其中的程式,也因如此,有一部分程式來自於網際網路,如果您覺得這侵犯了您的合法權益,請聯絡
刪除。
對於給您造成的不便和困擾,我表示深深的歉意。
本系列文章僅用於學習,禁止任何人或組織用於商業用途。
本系列文章中,標記*的為選學演算法,在
中較少涉及。
動態規劃
簡單線性動態規劃
LIS(最長上升子序列)
【簡介】
最長上升子序列( , ),在電腦科學上是指一個序列中最長的單調遞增的子序列。
【程式碼實現】
樸素方法
#include<cstdio>
#include<iostream>
using namespace std;
int n,a[5001],f[5001]={0,1},ans;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),f[i]=1;
for(int i=2;i<=n;i++){
for(int j=1;j<i;j++)
if(a[j]<a[i])f[i]=max(f[i],f[j]+1);
ans=max(ans,f[i]);
}
printf("%d",ans);
return 0;
}
複雜度
貪心實現
#include<cstdio>
#include<algorithm>
using namespace std;
int n,f[1000001],len,x;
int main(){
scanf("%d%d",&n,&x);
f[++len]=x;
for(int i=2;i<=n;i++){
scanf("%d",&x);
if(x>f[len]) f[++len]=x;
else f[lower_bound(f+1,f+len+1,x)-f]=x;
}
printf("%d",len);
return 0;
}
複雜度
LCS(最長公共子序列)
【簡介】
是 的縮寫,即最長公共子序列。一個序列,如果是兩個或多個已知序列的子序列,且是所有子序列中最長的,則為最長公共子序列。
【程式碼實現】
樸素做法
#include<cstdio>
#include<algorithm>
using namespace std;
int n,a[1007],b[1007],dp[1007][1007];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) scanf("%d",&b[i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(a[i]==b[j]) f[i][j]=max(f[i][j],f[i-1][j-1]+1);
else f[i][j]=max(f[i-1][j],f[i][j-1]);
printf("%d",f[n][n]);
return 0;
}
複雜度
利用 優化
#include<iostream>
#include<ctype.h>
#include<cstdio>
#include<algorithm>
using namespace std;
inline int read(){
int x=0,f=0;char ch=getchar();
while(!isdigit(ch))f|=ch=='-',ch=getchar();
while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
return f?-x:x;
}
int a,b[100007],Transformation[1000007],f[1000007];
int main(){
int n=read();
for(int i=1;i<=n;++i)a=read(),Transformation[a]=i;
for(int i=1;i<=n;++i)b[i]=read(),b[i]=Transformation[b[i]];
int o=1;
f[o]=b[o];
for(int i=2;i<=n;++i){
if(b[i]>f[o])f[++o]=b[i];
else f[upper_bound(f+1,f+o+1,b[i])-f]=b[i];
}
cout<<o;
return 0;
}
複雜度
LCIS(最長公共上升子序列)
【簡介】
給定兩個整數序列,求它們的最長上升公共子序列。
//Cogs 1669神祕的咒語
#include<iostream>
#include<cstdio>
#include<ctype.h>
#include<cstring>
using namespace std;
inline int read(){
int x=0,f=0;char ch=getchar();
while(!isdigit(ch))f|=ch=='-',ch=getchar();
while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
return f?-x:x;
}
int a[507],b[507],f[507];
int main(){
freopen("codes.in","r",stdin);
freopen("codes.out","w",stdout);
int T=read();
while(T--){
memset(f,0,sizeof f);
int n=read(),ans=0;
for(int i=1;i<=n;++i)a[i]=read();
int m=read();
for(int i=1;i<=m;++i)b[i]=read();
for(int i=1;i<=n;++i){
int Max=0;
for(int j=1;j<=m;++j){
if(a[i]>b[j])Max=max(Max,f[j]);
if(a[i]==b[j])f[j]=Max+1;
}
}
for(int i=1;i<=m;++i)ans=max(ans,f[i]);
printf("%d\n",ans);
}
fclose(stdin);fclose(stdout);
return 0;
}
複雜度
最大子段和問題
【簡介】
給定
個整數(可能為負數)組成的序列
求該序列如
的子段和的最大值。當所給的整數均為負數時定義子段和為
,依此定義,所求的最優值為: