《现代程序设计》9.9日课后总结
2013-09-10 14:57
260 查看
邹老师的第一门课上小测了最大子矩阵的问题,课堂上只想到了O(n^2*m^2)的算法
后来翻《编程之美》的时候翻到了这道题...今天下午研究了一下,到OJ上切了几道题,熟悉了动态规划在这个问题中的应用.
关于最大子段和有一种变形是最大m子段和,http://acm.hdu.edu.cn/showproblem.php?pid=1024,就是在原有的基础上求m段子段的和,这里建立动态规划方程,dp[i][j]表示前j个数(包括第j个数)组成i段的和的最大值,那么根据第j个数是否独立成组得到转移方程为dp[i][j]=max(dp[i-1][j-1]+a[j],dp[i-1][k]+a[j]),0<k<j,这里dp[i][]只和dp[i-1][]有关,用一维数组就可以表示,同时dp[i-1][k]表示1~j-1中构成i-1组的最大值,即前一组的值,那么可以在循环中求出,所以复杂度为O(n*m)
根据这道题那么poj2593,http://poj.org/problem?id=2593,就很容易解决了...就是将m替换为两段就好
我拿poj1050,http://poj.org/problem?id=1050,做了练习
暂时只能想到这些,以后遇到该问题的变形,比如像课后扩展那样对于矩阵可以首尾相连,二维扩展到三维、四维等等的问题,我会继续在这里更新。
后来翻《编程之美》的时候翻到了这道题...今天下午研究了一下,到OJ上切了几道题,熟悉了动态规划在这个问题中的应用.
一.最大子段和
书上已经将这种思想讲的很透彻,对基本的最大子段和的练习可以参照hdu1003题http://acm.hdu.edu.cn/showproblem.php?pid=1003,唯一的一点变形是这道题要求求出最大字段的起始位置和终止位置.#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #define INF 0x3f3f3f3f using namespace std; const int maxn=100005; int map[maxn]; int ans; int begin; int end; int n; void getmap() { for(int i=1;i<=n;i++) { cin>>map[i]; } } void work() { int tempsum=0; int tmpbegin=1; for(int i=1;i<=n;i++) { tempsum+=map[i]; if(tempsum>ans) { ans=tempsum; begin=tmpbegin; end=i; } if(tempsum<0) { tempsum=0; tmpbegin=i+1; } } } int main() { int T; cin>>T; for(int tt=1;tt<=T;tt++) { ans=-INF; cin>>n; getmap(); work(); cout<<"Case "<<tt<<":"<<endl; cout<<ans<<" "<<begin<<" "<<end<<endl; if(tt<T) { cout<<endl; } } return 0; }
关于最大子段和有一种变形是最大m子段和,http://acm.hdu.edu.cn/showproblem.php?pid=1024,就是在原有的基础上求m段子段的和,这里建立动态规划方程,dp[i][j]表示前j个数(包括第j个数)组成i段的和的最大值,那么根据第j个数是否独立成组得到转移方程为dp[i][j]=max(dp[i-1][j-1]+a[j],dp[i-1][k]+a[j]),0<k<j,这里dp[i][]只和dp[i-1][]有关,用一维数组就可以表示,同时dp[i-1][k]表示1~j-1中构成i-1组的最大值,即前一组的值,那么可以在循环中求出,所以复杂度为O(n*m)
/* dp[i][j]前j个数(包括第j个数,组成i组的和的最大值 dp[i][j]=max(dp[i-1][j-1]+map[j],dp[i-1][k]+map[j]),0<k<j 即根据第j个数是否单独成组划分状态 前i组仅与前i-1组有关,这里用一维数组就好 而dp[i-1][k]其实就是上一组中从0-j-1中划分为i-1组的最大值 */ #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #define INF 0x3f3f3f3f using namespace std; const int maxn=1000005; __int64 map[maxn]; __int64 dp[maxn]; __int64 prev[maxn]; __int64 ans; int m; int n; void getmap() { dp[0]=0; prev[0]=0; for(int i=1;i<=n;i++) { scanf("%I64d",&map[i]); dp[i]=0; prev[i]=0; } } void work() { for(int i=1;i<=m;i++) { ans=-INF; for(int j=i;j<=n;j++) { dp[j]=max(dp[j-1],prev[j-1])+map[j]; prev[j-1]=ans; ans=max(ans,dp[j]); } } } int main() { while(scanf("%d%d",&m,&n)!=EOF) { getmap(); work(); printf("%I64d\n",ans); } return 0; }
根据这道题那么poj2593,http://poj.org/problem?id=2593,就很容易解决了...就是将m替换为两段就好
/* dp[i][j]前j个数(包括第j个数,组成i组的和的最大值 dp[i][j]=max(dp[i-1][j-1]+map[j],dp[i-1][k]+map[j]),0<k<j 即根据第j个数是否单独成组划分状态 前i组仅与前i-1组有关,这里用一维数组就好 而dp[i-1][k]其实就是上一组中从0-j-1中划分为i-1组的最大值 */ #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #define INF 0x3f3f3f3f using namespace std; const int maxn=1000005; int map[maxn]; int dp[maxn]; int prev[maxn]; int ans; int m; int n; void getmap() { dp[0]=0; prev[0]=0; for(int i=1;i<=n;i++) { scanf("%d",&map[i]); dp[i]=0; prev[i]=0; } } void work() { for(int i=1;i<=m;i++) { ans=-INF; for(int j=i;j<=n;j++) { dp[j]=max(dp[j-1],prev[j-1])+map[j]; prev[j-1]=ans; ans=max(ans,dp[j]); } } } int main() { while(scanf("%d",&n)!=EOF&&n) { m=2; getmap(); work(); printf("%d\n",ans); } return 0; }
二.最大子矩阵
最大子矩阵的算法就是将第k列中第i行到j行的数的和求出,然后套用一维的算法就好我拿poj1050,http://poj.org/problem?id=1050,做了练习
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #define INF 0x3f3f3f3f using namespace std; const int maxn=105; int map[maxn][maxn]; int sum[maxn][maxn]; int ans; int n; void getmap() { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { cin>>map[i][j]; } } } void getsum() { memset(sum,0,sizeof(sum)); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+map[i][j]; } } } void work() { ans=-INF; for(int i=1;i<=n;i++) { for(int j=i;j<=n;j++) { int start=sum[j] -sum[i-1] -sum[j][n-1]+sum[i-1][n-1]; int all=start; for(int k=n-1;k>=1;k--) { if(start<0) { start=0; } start+=sum[j][k]-sum[i-1][k]-sum[j][k-1]+sum[i-1][k-1]; all=max(all,start); } ans=max(ans,all); } } } int main() { while(cin>>n) { getmap(); getsum(); work(); cout<<ans<<endl; } return 0; }
暂时只能想到这些,以后遇到该问题的变形,比如像课后扩展那样对于矩阵可以首尾相连,二维扩展到三维、四维等等的问题,我会继续在这里更新。
相关文章推荐
- 多用户权限管理(课后总结)
- 创新营销-课后总结
- 数据结构之第二章 算法分析总结 及 课后题答案
- C和指针课后练习题总结
- 周志华机器学习第一章总结及课后答案参考
- caffe《学习笔记一》——《caffe21天实战》课后习题6.4网上解法总结
- 软件工程课后总结与反思
- 曾经做过的40道程序设计课后习题总结
- 20145319 《信息安全系统设计基础》第十三周课后总结
- 模拟CMOS集成电路 课后习题总结(2.1)
- C#课后作业总结
- (2016秋数据结构课后练习题总结)02-线性结构4 Pop Sequence (25分)
- 集成项目第四课课后总结
- 嵌入式系统 课后实验总结
- 3月31java课后总结
- 关于《Java读书笔记》第六章课后习题选择题总结与疑问
- 20145319 《信息安全系统设计基础》第十四周课后总结
- 周志华《机器学习》第一章总结+课后习题
- 20145329 《JAVA程序设计》课后习题代码编写总结
- CSDN培训第二节课课后总结