Description
在给出的矩阵中,选出 k 个* * * * 的矩阵,求最* *。
Input
矩阵的信息 + k, 与模样。
Output
答案。
Solution :
这是一道 DP 题,本来在考场上,我是没有想出一个比较好的 DP 的,但是由于从最大 m 子段和,得到了启示,当然这道题可以花式 DP, 你
n3k
,
n2k
, 还是
nk
都可以,这里我就讲一下我的做法,和一位大佬的
nk
的做法, 当然我的算法亦可以优化到
nk
,只需要一点小小的优化就可以了。
这里先说一下我的 DP, 记
DP[i][k][0∼3]
表示扫到
i
行,并且要选
首先我们先看一看DP[i][k][3] 是怎么转移的 :
1.与 i - 1 行的合并起来,能够合并的情况只有当i - 1行也是 3 的连通情况一种:
2.i行是独立成一个矩阵是,可以有前面的所有的k - 1情况更新过来 :
接下来是DP[i][k][2]的转移 :
1.可以由k - 2的所有状态转移 :
2.可以由k - 1的连通情况为 0, 1, 2 的状态转移 :
3.可以由 k 个矩阵 2 状态转移:
然后是DP[i][k][1]的转移 :
1.可以由所有的k - 1的状态转移 :
2.可以由 k 个矩阵的 1 的连通情况转移过来 :
接下来是要讲DP[i][k][0],但是这类的情况与上个状态是相似的,所以这里我就列方程:
好了这就是所有的转移,至于如何优化到 nk 我们可以看到,一个DP需要最多需要 k - 1的所有状态,所以我们只需要记录上一次DP的最大值,就不用再次遍历了。
至于大佬的做法是多定了一维,表示不选这样就不用记录最大值直接 O(n) 扫就完了,当然维越多写得越复杂,考虑的越多。
Code:
我的,希望你们喜欢。。。。。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <ctime>
#include <map>
#include <vector>
using namespace std;
inline int read() {
int i = 0, f = 1;
char ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') f = -1; ch = getchar();
}
while(isdigit(ch)) {
i = (i << 3) + (i << 1) + ch - '0'; ch = getchar();
}
return i * f;
}
const int MAXN = 100 + 5;
int f[MAXN][15], dp[MAXN][15][4], a[MAXN], b[MAXN][2], pre[MAXN][2];
inline int get(int i, int k) {
return max(dp[i][k][0], max(dp[i][k][1], max(dp[i][k][2], dp[i][k][3])));
}
inline int get1(int i, int k) {
return max(dp[i][k][0], max(dp[i][k][1], dp[i][k][3]));
}
inline int get2(int i, int k) {
return max(dp[i][k][0], max(dp[i][k][1], dp[i][k][2]));
}
int main() {
freopen("matrix.in", "r", stdin);
//freopen("matrix.out", "w", stdout);
int n = read(), m = read(), K = read();
if(m == 1) {
for(int i = 1; i <= n; ++i) a[i] = read();
for(int k = 1; k <= K; ++k) {
for(int i = 1; i <= n; ++i) {
f[i][k] = -0x3f3f3f3f;
if(i >= k) {
f[i][k] = max(f[i][k], f[i - 1][k] + a[i]);
for(int j = 1; j <= i - 1; ++j)
f[i][k] = max(f[i][k], f[j][k - 1] + a[i]);
}
}
}
int ans = -0x3f3f3f3f;
for(int i = K; i <= n; ++i)
ans = max(ans, f[i][K]);
printf("%d\n", ans);
}
else {
for(int i = 1; i <= n; ++i)
for(int j = 0; j < m; ++j)
b[i][j] = read();
for(int i = 1; i <= n; ++i)
for(int j = 0; j < m; ++j)
pre[i][j] = pre[i - 1][j] + b[i][j];
for(int k = 1; k <= K; ++k)
for(int i = 1; i <= n; ++i) {
dp[i][k][0] = dp[i][k][1] = dp[i][k][2] = dp[i][k][3] = -0x3f3f3f3f;//3状态是并在一起
if(i * 2 >= k) {
dp[i][k][3] = max(dp[i][k][3], get(i - 1, k - 1) + b[i][0] + b[i][1]);
dp[i][k][3] = max(dp[i][k][3], dp[i - 1][k][3] + b[i][0] + b[i][1]);
if(k >= 2) {
dp[i][k][2] = max(dp[i][k][2], get(i - 1, k - 2) + b[i][0] + b[i][1]);
dp[i][k][2] = max(dp[i][k][2], dp[i - 1][k][2] + b[i][0] + b[i][1]);
dp[i][k][2] = max(dp[i][k][2], get2(i - 1, k - 1) + b[i][0] + b[i][1]);
}
for(int j = 1; j <= i - 2; ++j) {
dp[i][k][3] = max(dp[i][k][3], get(j, k - 1) + b[i][0] + b[i][1]);
dp[i][k][2] = max(dp[i][k][2], get(j, k - 2) + b[i][0] + b[i][1]);
}
}
if(i * 2 - 1 >= k) {
dp[i][k][0] = max(dp[i][k][0], dp[i - 1][k][0] + b[i][0]);
dp[i][k][1] = max(dp[i][k][1], dp[i - 1][k][1] + b[i][1]);
dp[i][k][0] = max(dp[i][k][0], dp[i - 1][k][2] + b[i][0]);
dp[i][k][1] = max(dp[i][k][1], dp[i - 1][k][2] + b[i][1]);
for(int j = 1; j <= i - 1; ++j) {
dp[i][k][0] = max(dp[i][k][0], get(j, k - 1) + b[i][0]);
dp[i][k][1] = max(dp[i][k][1], get(j, k - 1) + b[i][1]);
int now1 = -0x3f3f3f3f, now2 = -0x3f3f3f3f;
/*for(int l = j - 1; l <= i - 1; ++l)
now1 = max(now1, pre[i][0] - pre[l][0]), now2 = max(now2, pre[i][1] - pre[l][1]); //cout<<now1<<' '<<now2<<'\n';
dp[i][k][0] = max(dp[i][k][0], dp[j][k - 1][1] + now1);
dp[i][k][1] = max(dp[i][k][1], dp[j][k - 1][0] + now2);*/
}
}
}
int ans = -0x3f3f3f3f;
for(int i = 1; i <= n; ++i)
ans = max(ans, get(i, K));//printf("%d %d %d %d\n", dp[i][2][0], dp[i][2][1], dp[i][2][2], dp[i][2][3]);
printf("%d\n", ans);
}
}
Hart’s code
#include <cstdio>
#include <cstring>
inline int getch() {
static int size = 0, pt = 0;
static char buf[1048576];
if((size == pt) && (pt = buf[size = fread(buf, sizeof(char), 1048575, stdin)] = '\0', size == 0))
return EOF;
return buf[pt++];
}
inline int get_int() {
register int ch, flag = 1, x;
for(ch = getch(); (unsigned)(ch ^'0') > 9; ch = getch()) if(ch == '-') flag = -1;
if(ch == EOF) return EOF;
for(x = ch ^ '0', ch = getch(); (unsigned)(ch ^ '0') < 10; ch = getch())
x = (x << 3) + (x << 1) + (ch ^ '0');
return x * flag;
}
struct IN {
const IN& operator >> (char &ch) const { return ch = getch(), *this; }
const IN& operator >> (int &x) const { return x = get_int(), *this; }
} in;
const int INF = 0x7F7F7F7F, NINF = 0x80808080;
int N, M, K, A[105][2],
DP[101][11][5], MaxDP[101][11];
inline void init() {
N = get_int();
M = get_int();
K = get_int();
for(register int i = 1; i <= N; ++i)
for(register int j = 0; j < M; ++j) {
A[i][j] = get_int();
}
}
inline int Max(register int a, register int b) { return a < b ? b : a; }
inline void solve1() {
for(register int i = 1; i <= N; ++i)
for(register int j = 0; j <= K; ++j) {
DP[i][j][0] = MaxDP[i - 1][j];
DP[i][j][1] = Max(DP[i - 1][j][1], (j ? MaxDP[i - 1][j - 1] : NINF));
if(DP[i][j][1] != NINF) DP[i][j][1] += A[i][0];
MaxDP[i][j] = Max(DP[i][j][0], DP[i][j][1]);
}
printf("%d\n", MaxDP[N][K]);
}
inline void solve() {
memset(DP[0], 0x80, sizeof(DP[0]));
memset(MaxDP[0], 0x80, sizeof(MaxDP[0]));
DP[0][0][0] = MaxDP[0][0] = 0;
if(M == 1) return solve1();
for(register int i = 1; i <= N; ++i)
for(register int j = 0; j <= K; ++j) {
DP[i][j][0] = MaxDP[i - 1][j];
DP[i][j][1] = Max(
Max(DP[i - 1][j][1], DP[i - 1][j][3]),
(j ? MaxDP[i - 1][j - 1] : NINF));
if(DP[i][j][1] != NINF) DP[i][j][1] += A[i][0];
DP[i][j][2] = Max(
Max(DP[i - 1][j][2], DP[i - 1][j][3]),
(j ? MaxDP[i - 1][j - 1] : NINF));
if(DP[i][j][2] != NINF) DP[i][j][2] += A[i][1];
DP[i][j][3] = Max(
DP[i - 1][j][3], Max(
(j ? Max(DP[i - 1][j - 1][1], DP[i - 1][j - 1][2]) : NINF),
(j > 1 ? MaxDP[i - 1][j - 2] : NINF)));
if(DP[i][j][3] != NINF) DP[i][j][3] += A[i][0] + A[i][1];
DP[i][j][4] = Max(
DP[i - 1][j][4],
(j ? MaxDP[i - 1][j - 1] : NINF));
if(DP[i][j][4] != NINF) DP[i][j][4] += A[i][0] + A[i][1];
MaxDP[i][j] = Max(Max(DP[i][j][0], DP[i][j][1]), Max(
Max(DP[i][j][2], DP[i][j][3]),
DP[i][j][4]));
}
printf("%d\n", MaxDP[N][K]);
}
int main() {
init();
solve();
return 0;
}