2020牛客多校第六场C题Combination of Physics and Maths(基础算法DP)
题目链接 https://ac.nowcoder.com/acm/contest/5671/C
题意:输入一个n*m的矩阵,找一个值最大的 (子矩阵的和/子矩阵最后一行的和),输出
题解:比赛时联想到以前写过的最大子矩阵和,就是用dp来写,
一维数组a[i]的最大子段和我们可以用dp[i]=max(dp[i-1]+a[i],a[i])来转移
int solve(){ int maxx=0; for(int i=0;i<n;i++){ dp[i]=max(dp[i-1]+a[i],a[i]); maxx=max(dp[i],maxx); } return maxx; }
二维矩阵的最大子矩阵和,我们把他转化为一维的子段和,就是把第i行的值加到第j行,再跑一维的最大子段和,时间复杂度O(n*3),比赛时超时。
#include<bits/stdc++.h> using namespace std; const int N=215; int a[N][N]; double b[N][N],dp[N]; double mx=0; int n,t,m; void solve(int j){ memset(dp,0,sizeof(dp)); int ls,ns; for(int i=1;i<=m;i++){ dp[i]=max(b[j][i] / a[j][i], (dp[i-1]*ls+b[j][i]) /(ls+a[j][i]) ); if( b[j][i] / a[j][i] > (dp[i-1]*ls+b[j][i]) /(ls+a[j][i]) ){ ls=a[j][i]; }else{ ls+=a[j][i]; } mx=max(mx,dp[i]); } } int main(){ scanf("%d",&t); while(t--){ mx=0.0; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ scanf("%d",&a[i][j]); } } for(int i=1;i<=n;i++){ //从第i行开始加 memset(b,0,sizeof(b)); for(int j=1;j<=n;j++){ //加到第j行 for(int k=1;k<=m;k++){ //第j行各个列的值 b[j][k]=a[j][k]+b[j-1][k]; } solve(j); } } printf("%.8lf\n",mx); } }
再看题意我们可以理解,这个只是求列的最大值,所以我们直接累加到n行,这样就能过,
#include<bits/stdc++.h> using namespace std; const int N=215; int a[N][N]; double b[N][N],dp[N]; double mx=0; int n,t,m; void solve(int j){ memset(dp,0,sizeof(dp)); int ls,ns; for(int i=1;i<=m;i++){ dp[i]=max(b[j][i] / a[j][i], (dp[i-1]*ls+b[j][i]) /(ls+a[j][i]) ); if( b[j][i] / a[j][i] > (dp[i-1]*ls+b[j][i]) /(ls+a[j][i]) ){ ls=a[j][i]; }else{ ls+=a[j][i]; } mx=max(mx,dp[i]); } } int main(){ scanf("%d",&t); while(t--){ mx=0.0; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ scanf("%d",&a[i][j]); } } //for(int i=1;i<=n;i++){ //从第i行开始加 memset(b,0,sizeof(b)); for(int j=1;j<=n;j++){ //加到第j行 for(int k=1;k<=m;k++){ //第j行各个列的值 b[j][k]=a[j][k]+b[j-1][k]; } solve(j); } //} printf("%.8lf\n",mx); } }
还有一种思想a/b<(a+c)/(b+d)<c/d( 单列一定大于多列)
解释如下: 设a/b>c/d,则a∗d>b∗c,左右同时加上a∗b,为a∗d+a∗b>b∗c+a∗b,即为a∗(b+d)/b∗(a+c),移项,a/b>(a+c)/(b+d)
所以单列更优
所以只要找到每列最大即可
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int a[210][210]; int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int t,n,m; double k; cin>>t; while(t--) { cin>>n>>m; double ans=1e-6; for(int i=0;i<n;i++) for(int j=0;j<m;j++) { cin>>a[i][j]; } for(int j=0;j<m;j++) { k=0; for(int i=0;i<n;i++) { k+=a[i][j]; ans=max(ans,k*1.0/a[i][j]); } } printf("%.8lf\n",ans); } return 0; }

浙公网安备 33010602011771号