【习题】动态规划!
本文中的习题来自 Loi_DQS dalao整理的DP学习资料
1.【codevs1220】数字三角形问题
记忆化搜索:
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 const int sz=1000+50; 5 int map[sz][sz],dp[sz][sz]; 6 int n; 7 int dfs(int i,int j) 8 { 9 if(i==n) return map[i][j]; 10 if(dp[i+1][j]==0) dp[i+1][j]=dfs(i+1,j); 11 if(dp[i+1][j+1]==0) dp[i+1][j+1]=dfs(i+1,j+1); 12 return dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+map[i][j]; 13 } 14 int main() 15 { 16 scanf("%d",&n); 17 for(int i=1;i<=n;i++) 18 for(int j=1;j<=i;j++) 19 scanf("%d",&map[i][j]); 20 printf("%d",dfs(1,1)); 21 return 0; 22 }
顺推:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int sz=1000+50; 6 int map[sz][sz],dp[sz][sz]; 7 int main() 8 { 9 int n; 10 scanf("%d",&n); 11 for(int i=1;i<=n;i++) 12 for(int j=1;j<=i;j++) 13 scanf("%d",&map[i][j]); 14 for(int i=1;i<=n;i++) 15 for(int j=1;j<=i;j++) 16 dp[i][j]=max(dp[i-1][j],dp[i-1][j-1])+map[i][j]; 17 int ans=-999; 18 for(int i=1;i<=n;i++) 19 ans=max(ans,dp[n][i]); 20 printf("%d",ans); 21 return 0; 22 }
逆推:
#include<cstdio> #include<algorithm> using namespace std; const int sz=1000+50; int map[sz][sz],dp[sz][sz]; int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) for(int j=1;j<=i;j++) scanf("%d",&map[i][j]); for(int i=n;i>=0;i--) for(int j=1;j<=i;j++) dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+map[i][j]; printf("%d",dp[1][1]); return 0; }
2.【codevs1576】最长上升子序列(LIS)问题
常规做法
#include<cstdio> #include<algorithm> using namespace std; const int sz=5000+50; int num[sz],dp[sz]; int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&num[i]); int ans=0; for(int i=1;i<=n;i++) { dp[i]=1;//初始化 以i结尾的LIS长度最小为1 for(int j=1;j<i;j++) if(num[j]<num[i]) dp[i]=max(dp[i],dp[j]+1); ans=max(ans,dp[i]); } printf("%d",ans); return 0; }
O(nlogn)做法。。。
3.方格取数问题
#include<cstdio> #include<algorithm> using namespace std; const int sz=5000+50; int map[sz][sz],dp[sz][sz]; int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&map[i][j]); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { dp[i][j]=max(dp[i-1][j],dp[i][j-1])+map[i][j]; } printf("%d",dp[n][m]); return 0; }
4.【codevs1102】01背包问题
常规做法
#include<cstdio> #include<algorithm> using namespace std; const int sz=1000+100; struct node{ int tim,val; }th[sz]; int dp[sz][sz]; int main() { int t,m; scanf("%d%d",&t,&m); for(int i=1;i<=m;i++) scanf("%d%d",&th[i].tim,&th[i].val); for(int i=1;i<=m;i++) for(int j=0;j<=t;j++) { if(j>=th[i].tim) dp[i][j]=max(dp[i-1][j],dp[i-1][j-th[i].tim]+th[i].val); else dp[i][j]=dp[i-1][j]; } printf("%d",dp[m][t]); return 0; }
滚动数组
#include<cstdio> #include<algorithm> using namespace std; const int sz=1000+10; struct node{ int tim,val; }th[sz]; int dp[sz]; int main() { int t,m; scanf("%d%d",&t,&m); for(int i=1;i<=m;i++) { int tim,val; scanf("%d%d",&tim,&val); th[i].tim=tim,th[i].val=val; } for(int i=1;i<=m;i++) for(int j=t;j>=th[i].tim;j--) { dp[j]=max(dp[j],dp[j-th[i].tim]+th[i].val); } printf("%d",dp[t]); return 0; }
5.【luogu1616】完全背包问题
滚动数组
#include<cstdio> #include<algorithm> using namespace std; const int sz=100000+10; int c[sz/10],v[sz/10],dp[sz]; int main() { int t,m; scanf("%d%d",&t,&m); for(int i=1;i<=m;i++) scanf("%d%d",&c[i],&v[i]); for(int i=1;i<=m;i++) for(int j=c[i];j<=t;j++) dp[j]=max(dp[j],dp[j-c[i]]+v[i]); printf("%d",dp[t]); return 0; }
6.最长公共子序列
#include<cstdio> #include<algorithm> using namespace std; typedef long long ll; const int sz=3000+10; ll a[sz],b[sz]; int dp[sz][sz]; int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); dp[i][0]=0; } for(int i=1;i<=n;i++) { scanf("%lld",&b[i]); dp[0][i]=0; } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { if(a[i]==b[j]) dp[i][j]=max(dp[i-1][j-1]+1,max(dp[i][j-1],dp[i-1][j])); else dp[i][j]=max(dp[i-1][j-1],max(dp[i][j-1],dp[i-1][j])); } printf("%d",dp[n][n]); return 0; }
7.区间DP 【codevs1048】石子归并问题
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int sz=100+10; int a[sz],dp[sz][sz],sum[sz]; int main() { int n; scanf("%d",&n); memset(dp,63,sizeof(dp));//求最大值,先初始化 for(int i=1;i<=n;i++) { scanf("%d",&a[i]); sum[i]=sum[i-1]+a[i]; dp[i][i]=0;//边界条件 } for(int i=n;i>0;i--) for(int j=i+1;j<=n;j++) for(int k=i;k<j;k++) dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]); printf("%d",dp[1][n]); return 0; }
8.【codevs2152】滑雪
#include<cstdio> #include<algorithm> using namespace std; const int sz=100+10; int map[sz][sz],dp[sz][sz]; int dx[5]={0,0,1,0,-1}; int dy[5]={0,1,0,-1,0}; int r,c; int dfs(int i,int j) { if(dp[i][j]) return dp[i][j]; int ans=1; for(int k=1;k<=4;k++) { int x=i+dx[k],y=j+dy[k]; if(x>0&&x<=r&&y>0&&y<=c&&map[i][j]>map[x][y]) ans=max(ans,dfs(x,y)+1); } return dp[i][j]=ans; } int main() { scanf("%d%d",&r,&c); for(int i=1;i<=r;i++) for(int j=1;j<=c;j++) scanf("%d",&map[i][j]); int ans=0; for(int i=1;i<=r;i++) for(int j=1;j<=c;j++) ans=max(ans,dfs(i,j)); printf("%d",ans); return 0; }
9.
10.【codevs1044】拦截导弹
O(n^2)做法:
#include<cstdio> #include<algorithm> using namespace std; const int sz=100000+10; int a[sz],dp1[sz],dp2[sz],tot; int main() { while(scanf("%d",&a[++tot])!=EOF); int ans=0; for(int i=1;i<tot;i++) { dp1[i]=1; for(int j=1;j<i;j++) { if(a[j]>=a[i]) dp1[i]=max(dp1[i],dp1[j]+1); } ans=max(ans,dp1[i]); } printf("%d\n",ans); ans=0; for(int i=1;i<tot;i++) { dp2[i]=1; for(int j=1;j<i;j++) { if(a[j]<a[i]) dp2[i]=max(dp2[i],dp2[j]+1); } ans=max(ans,dp2[i]); } printf("%d",ans); return 0; }
O(nlogn)做法:

浙公网安备 33010602011771号