在给出的矩阵中,选出 k 个* * * * 的矩阵,求最* *。
矩阵的信息 + k, 与模样。
答案。
这是一道 DP 题,本来在考场上,我是没有想出一个比较好的 DP 的,但是由于从最大 m 子段和,得到了启示,当然这道题可以花式 DP, 你 n3k , n2k , 还是 nk 都可以,这里我就讲一下我的做法,和一位大佬的 nk 的做法, 当然我的算法亦可以优化到 nk ,只需要一点小小的优化就可以了。
这里先说一下我的 DP, 记 DP[i][k][0∼3] 表示扫到 i 行,并且要选 i 行里的数,时有 k 个矩阵的最大和, 0∼4 表示的 i 行的联通情况, 0 表示只选左边的数, 1 表示只选右边的数, 2 表示选两个数,但是两个数不属于同一个矩阵,3 表示选两个数,这两个数属于同一个矩阵, 通过这个我们可以得到转移方程,这样定义转移方程的思想有点像插头 DP。接下来我要写转移方程了,建议大家自己先自己推了再看。那么 :
首先我们先看一看DP[i][k][3] 是怎么转移的 :
1.与 i - 1 行的合并起来,能够合并的情况只有当i - 1行也是 3 的连通情况一种:
我的,希望你们喜欢。。。。。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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<
}
}
}
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
#include
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;
}