題目描述
有一個n*m的矩陣,恰好改變其中一個數變成給定的常數P,使得改變后的這個矩陣的最大子矩陣最大。
數據范圍
n,m<=300。
題解:
①如果沒有p,那么二維矩陣和就是一維最長連續子序列的DP升級就可以了:
設f[i][j][k]表示在i行j行之間1~k列這一個矩形中的最大子矩陣的值
轉移方程:f[i][j][k]=max(f[i][j][k-1]+sum[k],sum[k])
其中sum[k]表示(i,k)-(j,k)這一段一維序列的元素和。
上述在代碼實現的時候可以壓維,即覆蓋以前的答案。
②根據題意,加一維[1/0]表示到目前為止最優矩陣中有沒有點被更改了:
然后轉移同理,只是如果選擇修改,肯定是修改最小的數,所以使用RMQ或者暴力得出即可
#include <iostream> #include <cstdio> #include <fstream> #include <algorithm> #include <cmath> #include <deque> #include <vector> #include <queue> #include <string> #include <cstring> #include <map> #include <stack> #include <set> #define Max(a,b) a>b?a:b #define Min(a,b) a>b?b:a #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; int dir[4][2]= {{1,0},{-1,0},{0,1},{0,-1}}; const double eps = 1e-6; const double Pi = acos(-1.0); const int INF=0x3f3f3f3f; const int maxn = 310; int mat[maxn][maxn]; int minval[maxn]; int sum[maxn]; int dp[maxn][2]; int dp1(int* sum,int m,int p){ int ret = -INF; for(int i = 0; i < m; i++){ int minn = INF; int summ = 0; for(int j = i; j < m; j++){ summ += sum[j]; minn = min(minn,minval[j]); if(i == 0 && j == m-1){ ret = max(ret,summ - minn + p); }else{ int maxx = max(summ,summ - minn + p); ret = max(maxx,ret); } } } return ret; } int dp2(int* sum,int m,int p){ dp[0][0] = sum[0]; dp[0][1] = sum[0] - minval[0] +p; for(int i = 1; i < m; i++){ dp[i][0] = max(dp[i-1][0],0)+sum[i]; dp[i][1] = max(dp[i-1][1] + sum[i],max(dp[i-1][0],0) + sum[i] - minval[i] + p); } int ret = -INF; for(int i = 0; i < m; i++){ ret = max(ret,max(dp[i][0],dp[i][1])); } return ret; } int solve(int n,int m,int p){ int ans = -INF; for(int i = 0; i < n; i++){ fill(sum,sum+m+1,0); fill(minval,minval+m+1,INF); for(int j = i; j < n; j++){ for(int k = 0; k < m; k++){ sum[k] += mat[j][k]; minval[k] = min(minval[k],mat[j][k]); } if(i == 0 && j == n-1){ ans = max(ans,dp1(sum,m,p)); }else{ ans = max(ans,dp2(sum,m,p)); } } } return ans; } int main(){ int n,m,p; while(~scanf("%d%d%d",&n,&m,&p)){ for(int i = 0; i < n; i++){ for(int j = 0; j < m; j++){ scanf("%d",&mat[i][j]); } } printf("%d\n",solve(n,m,p)); } return 0; }//czy020202
我只想朝着遠方邊走邊唱,歌唱這生命美麗和迷惘。————汪峰《邊走邊唱》