[NOIP模拟] 矩阵

来源:互联网 发布:js elementHTML 编辑:程序博客网 时间:2024/06/15 20:41

Description

    在给出的矩阵中,选出 k 个* * * * 的矩阵,求最* *。

Input

    矩阵的信息 + k, 与模样。

Output

    答案。



Solution :

    这是一道 DP 题,本来在考场上,我是没有想出一个比较好的 DP 的,但是由于从最大 m 子段和,得到了启示,当然这道题可以花式 DP, 你 n3k, n2k, 还是 nk都可以,这里我就讲一下我的做法,和一位大佬的 nk 的做法, 当然我的算法亦可以优化到 nk,只需要一点小小的优化就可以了。
    这里先说一下我的 DP, 记 DP[i][k][03] 表示扫到 i 行,并且要选 i 行里的数,时有 k 个矩阵的最大和,04 表示的 i 行的联通情况, 0 表示只选左边的数, 1 表示只选右边的数, 2 表示选两个数,但是两个数不属于同一个矩阵,3 表示选两个数,这两个数属于同一个矩阵, 通过这个我们可以得到转移方程,这样定义转移方程的思想有点像插头 DP。接下来我要写转移方程了,建议大家自己先自己推了再看。那么 :


首先我们先看一看DP[i][k][3] 是怎么转移的 :
    1.与 i - 1 行的合并起来,能够合并的情况只有当i - 1行也是 3 的连通情况一种:

DP[i][k][3]=DP[i1][k][3]+a[i][0]+a[i][1]

    2.i行是独立成一个矩阵是,可以有前面的所有的k - 1情况更新过来 :
DP[i][k][3]=max(DP[j][k1][03])+a[i][0]+a[i][1](1ji1)

接下来是DP[i][k][2]的转移 :
    1.可以由k - 2的所有状态转移 :
DP[i][k][2]=max(DP[j][k2][03])+a[i][0]+a[i][1](1ji1)

    2.可以由k - 1的连通情况为 0, 1, 2 的状态转移 :
DP[i][k][2]=max(DP[i][k1][0,1,2])+a[i][1]+a[i][0]

    3.可以由 k 个矩阵 2 状态转移:
DP[i][k][2]=DP[i1][k][2]+a[i][1]+a[i][0]

然后是DP[i][k][1]的转移 :
    1.可以由所有的k - 1的状态转移 :
DP[i][k][1]=max(DP[j][k1][03])+a[i][1](1ji1)

    2.可以由 k 个矩阵的 1 的连通情况转移过来 :
DP[i][k][1]=DP[i1][k][1]+a[i][1]

接下来是要讲DP[i][k][0],但是这类的情况与上个状态是相似的,所以这里我就列方程:
DP[i][k][0]=max(DP[j][k1][03])+a[i][0](1ji1)
DP[i][k][0]=DP[i1][k][0]+a[i][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;}