动态规划(线性)
898. 数字三角形
https://www.acwing.com/problem/content/900/

#include<iostream> #include<cstring> #include<algorithm> using namespace std; const int N=510,INF=1e9; int n;int a[N][N],p[N][N]; int main() { cin>>n; for(int i=1;i<=n;i++) for(int j=1;j<=i;j++) cin>>a[i][j]; //初始化,便于后面更新 memset(p,-0x3f3f3f3f,sizeof p); //切记头一个初始化 p[1][1]=a[1][1]; for(int i=2;i<=n;i++) for(int j=1;j<=i;j++) p[i][j]=max(p[i-1][j-1]+a[i][j],p[i-1][j]+a[i][j]); //最大值在最后一排,但不一定是最后一个,需要求解 int res=-INF; for(int i=1;i<=n;i++) res=max(res,p[n][i]); cout<<res<<endl; return 0; }
最长子序列
https://www.acwing.com/problem/content/897/
(可以不相邻取子串)
#include<iostream> #include<algorithm> using namespace std; const int N=1010; int n;int a[N],p[N]; int main() { cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=n;i++) { p[i]=1;//只有a[i]一个数 for(int j=1;j<i;j++) { if(a[j]<a[i]) p[i]=max(p[i],p[j]+1); } } int ans=0; for(int i=1;i<=n;i++) ans=max(ans,p[i]); cout<<ans<<endl; return 0; }
//贪心求法 #include<iostream> using namespace std; const int N=100010; int a[N],p[N];int n; int main() { cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; int len=1;p[1]=a[1]; for(int i=2;i<=n;i++) { int l=0,r=len;//二分找到位置 while(l<r){ int mid=l+r+1>>1; if(p[mid]<a[i]) l=mid; else r=mid-1; } len=max(len,r+1);//更新最大长度 p[r+1]=a[i];//长度增加,下一个位置的最小值变化,因为更新的数肯定小于下一个值 } cout<<len<<endl; return 0; }
求路径
#include<iostream> #include<algorithm> using namespace std; const int N=1010; int n;int a[N],p[N],s[N]; int main() { cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=n;i++) { p[i]=1;//只有a[i]一个数 s[i]=0; for(int j=1;j<i;j++) { if(a[j]<a[i]) { if(p[j]+1>p[i]) { p[i]=p[j]+1; s[i]=j;//记录上一个位置的下标 } } } } int ans=0;int k; for(int i=1;i<=n;i++){ if(p[i]>ans){ ans=p[i]; k=i; } } cout<<ans<<endl; for(int i=k;i!=0;i=s[i])//倒叙遍历输出 cout<<a[i]<<" "; return 0; }
最长公共子序列(字符串)
https://www.acwing.com/problem/content/899/


#include<iostream> #include<algorithm> using namespace std; const int N=1010; char a[N],b[N]; int p[N][N]; int n,m; int main() { cin>>n>>m; scanf("%s%s", a+1, b+1); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ p[i][j]=max(p[i-1][j],p[i][j-1]); if(a[i]==b[j]) p[i][j]=max(p[i][j],p[i-1][j-1]+1); } } cout<<p[n][m]<<endl; return 0; }
分组DP
https://www.acwing.com/problem/content/284/
#include<iostream> using namespace std; const int N=1010; int sum[N];int a[N];int p[N][N]; int main() { int n;cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i]; for(int len=2;len<=n;len++){//区间长度 for(int i=1;i+len-1<=n;i++){//枚举区间开头 int j=i+len-1;//区间结尾 p[i][j]=1e9+10; for(int k=i;k<j;k++)//区间内不同分段 { p[i][j]=min(p[i][j],p[i][k]+p[k+1][j]+sum[j]-sum[i-1]); } } } cout<<p[1][n]<<endl; return 0; }
最短编辑距离
https://www.acwing.com/problem/content/904/

#include<iostream> #include<algorithm> using namespace std; const int N=1010; int n,m;char a[N],b[N]; int f[N][N]; int main() { scanf("%d%s",&n,a+1); scanf("%d%s",&m,b+1); //因为存在i-1等操作,所以必须初始化0的位置 for(int i=0;i<=m;i++) f[0][i]=i; for(int j=0;j<=n;j++) f[j][0]=j; for(int i=1;i<=n;i++) for(int j=1;j<=m;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[n][m]<<endl; return 0; }
编辑距离
https://www.acwing.com/problem/content/901/
#include<iostream> #include<algorithm> #include<string.h> using namespace std; const int N=14,M=1010; int n,m;char str[M][N]; int f[N][N]; int comp_str(char a[],char b[]){ int la=strlen(a+1);int lb=strlen(b+1); for(int i=0;i<=la;i++) f[i][0]=i; for(int i=0;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); } return f[la][lb]; } int main() { scanf("%d%d",&n,&m); for(int i=0;i<n;i++) scanf("%s",str[i]+1); while(m--){ char s[N];int limt;int cnt=0; scanf("%s%d",s+1,&limt); for(int i=0;i<n;i++){ if(comp_str(str[i],s)<=limt) cnt++; } printf("%d\n",cnt); } return 0; }

浙公网安备 33010602011771号