BZOJ1084 [SCOI2005]最大子矩阵 动态规划
歡迎訪問~原文出處——博客園-zhouzhendong
去博客園看該題解
題目傳送門 - BZOJ1084
?
題意概括
這里有一個n*m的矩陣,請你選出其中k個子矩陣,使得這個k個子矩陣分值之和最大。注意:選出的k個子矩陣不能相互重疊。
輸入:第一行為n,m,k(1≤n≤100,1≤m≤2,1≤k≤10),接下來n行描述矩陣每行中的每個元素的分值(每個元素的分值的絕對值不超過32767)。
?
題解
注意到1<=m<=2!
如果m = 1 ,那么就是一個簡單的線性dp。
我們設dp[i][j]表示在前i個里面選出k個子矩陣的最大分值。
那么分兩種情況討論:
1. ?什么都不干: dp[i][j] = max(dp[i][j], dp[i-1][j])
2. 弄一個新的子矩陣: dp[i][j] = max(dp[i][j], dp[x][j - 1] + presum[i] - presum[x]) ?0<=x<i
時間復雜度O(kn2)
?
如果 m = 2 ,那么是一個稍微復雜一點的線性dp。
我們設dp[i][j][x]表示在第一列的前i個和第二列的前j個里面選出x個子矩陣的最大分值。
那么分幾種情況進行討論:
1. 什么都不干: dp[i][j][x] = max(dp[i][j][x], dp[i - 1][j][x], dp[i][j - 1][x])
2. 在第一列弄一個新的子矩陣: dp[i][j][x] = max(dp[i][j][x], dp[y][j][x - 1] + presum[i][1] - presum[y][1]) ?0<=y<i
3. 在第二列弄一個新的子矩陣: dp[i][j][x] = max(dp[i][j][x], dp[i][y][x - 1] + presum[j][2] - presum[y][2]) ?0<=y<j
4. 在第一、二列弄一個寬度為2的子矩陣: dp[i][j][x] = max(dp[i][j][x], dp[y][y][x - 1] + presum[i][1] - presum[y][1] + presum[j][2] - presum[y][2]) ?i = j 且 0<=y<i
時間復雜度O(kn3)
?
?
代碼
#include <cstring> #include <algorithm> #include <cstdlib> #include <cstdio> #include <cmath> using namespace std; const int N=100+5,M=5,K=10+5; const int Inf=1<<25; int n,m,k,a[N][M]; void solve1(){int dp[N][K],presum[N];for (int i=0;i<N;i++)for (int j=0;j<K;j++)dp[i][j]=-Inf;presum[0]=0;for (int i=1;i<=n;i++)presum[i]=presum[i-1]+a[i][1];dp[0][0]=0;int ans=-Inf;for (int i=0;i<=n;i++)for (int j=0;j<=k;j++){if (!i&&!j)continue;if (i)dp[i][j]=dp[i-1][j];if (!j)continue;for (int x=0;x<i;x++)dp[i][j]=max(dp[i][j],dp[x][j-1]+presum[i]-presum[x]);}printf("%d",dp[n][k]); } void solve2(){int dp[N][N][K],presum[N][M];presum[0][1]=presum[0][2]=0;for (int i=1;i<=n;i++){presum[i][1]=presum[i-1][1]+a[i][1];presum[i][2]=presum[i-1][2]+a[i][2];}for (int i=0;i<N;i++)for (int j=0;j<N;j++)for (int x=0;x<K;x++)dp[i][j][x]=-Inf;dp[0][0][0]=0;for (int i=0;i<=n;i++)for (int j=0;j<=n;j++)for (int x=0;x<=k;x++){if (!i&&!j&&!x)continue;if (i&&j)dp[i][j][x]=max(dp[i-1][j][x],dp[i][j-1][x]);else if (i)dp[i][j][x]=dp[i-1][j][x];else if (j)dp[i][j][x]=dp[i][j-1][x];if (!x)continue;for (int y=0;y<i;y++)dp[i][j][x]=max(dp[i][j][x],dp[y][j][x-1]+presum[i][1]-presum[y][1]);for (int y=0;y<j;y++)dp[i][j][x]=max(dp[i][j][x],dp[i][y][x-1]+presum[j][2]-presum[y][2]);if (i==j)for (int y=0;y<i;y++)dp[i][j][x]=max(dp[i][j][x],dp[y][y][x-1]+presum[i][1]-presum[y][1]+presum[j][2]-presum[y][2]);}printf("%d",dp[n][n][k]); } int main(){scanf("%d%d%d",&n,&m,&k);for (int i=1;i<=n;i++)for (int j=1;j<=m;j++)scanf("%d",&a[i][j]);if (m==1)solve1();elsesolve2();return 0; }?
轉載于:https://www.cnblogs.com/zhouzhendong/p/BZOJ1084.html
總結
以上是生活随笔為你收集整理的BZOJ1084 [SCOI2005]最大子矩阵 动态规划的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据库分离 附加 sqlserver
- 下一篇: lintcode-415-有效回文串