zoukankan      html  css  js  c++  java
  • 洛谷 P2331 [SCOI2005]最大子矩阵

    洛谷

    这一题,乍一眼看上去只想到了最暴力的暴力——大概(n^4)吧。

    仔细看看数据范围,发现(1 leq m leq 2),这就好办了,分两类讨论。

    我先打了(m=1)的情况,拿了30分。

    就相当于最大(k)段子段和。

    直接用(dp[i][j][0/1])数组表示第(i)个选了(j)段的最大值,0代表不选,1为选。

    那么状态转移方程也很简单:

    • (dp[i][j][1]=max(dp[i-1][j-1][0],dp[i-1][j][1])+t[i];)
    • (dp[i][j][0]=max(dp[i-1][j][0],dp[i-1][j][1]);)

    (m=2)的情况怎么弄呢?

    实际上设计好状态,状态转移方程就出来了。

    (f[i][j][0,1,2,3,4])表示第(i)行选(j)个矩阵的最大值。

    • (f[i][j][0])表示不选第(i)行。
    • (f[i][j][1])表示选第(i)行的左边一段。
    • (f[i][j][2])表示选第(i)行的右边一段。
    • (f[i][j][3])表示选第(i)行左边和右边,分别代表两个段。
    • (f[i][j][4])表示选第(i)行左右两边,只代表一段。

    那么状态转移方程也很好出来了。

    • (f[i][j][0]=max{f[i-1][j][0],f[i-1][j][1],f[i-1][j][2],f[i-1][j][3],f[i-1][j][4]};)

    • (f[i][j][1]=max{f[i-1][j-1][0],f[i-1][j][1],f[i-1][j-1][2],f[i-1][j][3], f[i-1][j-1][4]}+a[i][0];)

    • (f[i][j][2]=max{f[i-1][j-1][0],f[i-1][j-1][1],f[i-1][j][2],f[i-1][j][3], f[i-1][j-1][4]}+a[i][1];)

    • (f[i][j][4]=max{f[i-1][j-1][1],f[i-1][j-1][2],f[i-1][j][3]}+a[i][0]+a[i][1];)

    • (if~(j>=2)~f[i][j][3]=max{f[i][j][3],f[i-1][j-2][4]+a[i][0]+a[i][1]};)

    • (f[i][j][4]=max{f[i-1][j-1][0],f[i-1][j-1][1],f[i-1][j-1][2],f[i-1][j-1][3],f[i-1][j][4]}+a[i][0]+a[i][1];)

    那么状态转移方程出来了就上代码吧!

    那么多(max)连在一起真是美如画呀~

    #include <bits/stdc++.h>
    #define N 101
    #define K 11
    using namespace std;
    int n,m,k;
    const int mx=0x3f3f3f3f;
    
    int dp[N][K][2],t[N];
    void work1()
    {
        for (int i=1;i<=n;++i) cin>>t[i];
        for (int i=1;i<=n;++i)
            for (int j=1;j<=k;++j) {
                dp[i][j][1]=max(dp[i-1][j][1],dp[i-1][j-1][0])+t[i];
                dp[i][j][0]=max(dp[i-1][j][0],dp[i-1][j][1]);
            }
        cout<<max(dp[n][k][0],dp[n][k][1]);
    }
    
    int f[N][K][5],a[N][2];
    void work2()
    {
        memset(f,-mx,sizeof(f));
        for (int i=0;i<=n;i++)
            for (int j=0;j<=k;j++) f[i][j][0]=0;
        for (int i=1;i<=n;++i) cin>>a[i][0]>>a[i][1];
        for (int i=1;i<=n;++i)
            for (int j=1;j<=k;++j) {
                f[i][j][0]=max(f[i-1][j][0],max(f[i-1][j][1],max(f[i-1][j][2],max(f[i-1][j][3],f[i-1][j][4]))));
                f[i][j][1]=max(f[i-1][j-1][0],max(f[i-1][j][1],max(f[i-1][j-1][2],max(f[i-1][j][3],f[i-1][j-1][4]))))+a[i][0];
                f[i][j][2]=max(f[i-1][j-1][0],max(f[i-1][j-1][1],max(f[i-1][j][2],max(f[i-1][j][3],f[i-1][j-1][4]))))+a[i][1];
                f[i][j][3]=max(f[i-1][j-1][1],max(f[i-1][j-1][2],f[i-1][j][3]))+a[i][0]+a[i][1];
                if (j>1) f[i][j][3]=max(f[i][j][3],f[i-1][j-2][4]+a[i][0]+a[i][1]);
                f[i][j][4]=max(f[i-1][j-1][0],max(f[i-1][j-1][1],max(f[i-1][j-1][2],max(f[i-1][j-1][3],f[i-1][j][4]))))+a[i][0]+a[i][1];
            }
        cout<<max(f[n][k][0],max(f[n][k][1],max(f[n][k][2],max(f[n][k][3],f[n][k][4]))));
    }
    
    int main()
    {
        cin>>n>>m>>k;m!=2?work1():work2();
        return 0;
    }
    
  • 相关阅读:
    《算法竞赛入门经典》 例题35 生成元 (Digit Generator, ACM ICPC Seoul 2005,UVa)
    《算法竞赛入门经典》 例题35 生成元 (Digit Generator, ACM ICPC Seoul 2005,UVa)
    《算法竞赛入门经典》 例题35 生成元 (Digit Generator, ACM ICPC Seoul 2005,UVa)
    SVN分支
    SVN分支
    SVN 版本回退
    SVN 版本回退
    如何在excel中取消合并单元格后内容自动填充?
    如何在excel中取消合并单元格后内容自动填充?
    如何让自己像打王者荣耀一样发了疯、拼了命的学习?
  • 原文地址:https://www.cnblogs.com/fushao2yyj/p/9588347.html
Copyright © 2011-2022 走看看