[NOIP模拟] 矩阵

10 篇文章 0 订阅
1 篇文章 0 订阅

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值