1. 程式人生 > >[SCOI2005]最大子矩陣解題報告

[SCOI2005]最大子矩陣解題報告

[SCOI2005]最大子矩陣 解題報告

題目描述

這裡有一個n*m的矩陣,請你選出其中k個子矩陣,使得這個k個子矩陣分值之和最大。注意:選出的k個子矩陣不能相互重疊。

輸入輸出格式

輸入格式

第一行為n,m,k(1≤n≤100,1≤m≤2,1≤k≤10),接下來n行描述矩陣每行中的每個元素的分值(每個元素的分值的絕對值不超過32767)。

輸出格式:

只有一行為k個子矩陣分值之和最大為多少。

input

3 2 2 1 -3 2 3 -2 3

output

9

思路:

顯然這道題是一道與矩陣有關的DP 所以可以用一種叫 懸線法 的奇技淫巧 所謂懸線法就是先把每一行,每一列的狀態都給拓展出來,然後再變為矩陣進行合併

先求出字首和,方便轉移。 然後就是轉移了。

wait!!

有沒有注意到m<=2?? 當m=1時,很簡單。。

f[i][k]=max(f[i][k],f[j][k-1]+sum[1][i]-sum[1][j]);//代表在前i個數中
//分成k個所取得的最大值

當m=2時 就要用懸線法啦!! F[i][j][k]代表在第一行取i個,第二行取個,分成k個的最大值。 什麼都不做 先拓展第一行 然後第二行 最後合併

  for(int k=1;k<=K;k++)
            for(int i=1;i<=n;i++)
                for(int j=1;
j<=n;j++) { F[i][j][k]=max(F[i-1][j][k],F[i][j-1][k]);//不在這一個點取數 for(int l=0;l<i;l++) //拓展第一行 F[i][j][k]=max(F[i][j][k],F[l][j][k-1]+sum[1][i]-sum[1][l]); for(int l=0;l<j;l++)//拓展第二行 F[
i][j][k]=max(F[i][j][k],F[i][l][k-1]+sum[2][j]-sum[2][l]); if(i==j)//i==j時就是一個矩陣啦,要合併了。 for(int l=0;l<i;l++) F[i][j][k]=max(F[i][j][k], F[l][l][k-1]+sum[1][i]-sum[1][l]+sum[2][j]-sum[2][l]); }

應該都懂了吧??

完整程式碼

#include<bits/stdc++.h>
using namespace std;
#define maxn 105
#define INF 0x3f3f3f

int n,m,K,x;
int f[maxn][maxn];
int F[maxn][maxn][maxn];
int sum[4][maxn];

int main()
{
    scanf("%d%d%d",&n,&m,&K);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&x),sum[j][i]=sum[j][i-1]+x;//字首和
    if(m==1)
    {
        //memset(f,-INF,sizeof(f));
        for(int k=1;k<=K;k++)
            for(int i=1;i<=n;i++)
            {
                f[i][k]=f[i-1][k];
                for(int j=0;j<i;j++)
                    f[i][k]=max(f[i][k],f[j][k-1]+sum[1][i]-sum[1][j]);
            }
        printf("%d\n",f[n][K]);
        return 0;
    }
    else
    {
        //memset(F,-INF,sizeof(F));
        for(int k=1;k<=K;k++)
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                {
                    F[i][j][k]=max(F[i-1][j][k],F[i][j-1][k]);
                    for(int l=0;l<i;l++) 
                        F[i][j][k]=max(F[i][j][k],F[l][j][k-1]+sum[1][i]-sum[1][l]);
                    for(int l=0;l<j;l++)
                        F[i][j][k]=max(F[i][j][k],F[i][l][k-1]+sum[2][j]-sum[2][l]);
                    if(i==j)
                        for(int l=0;l<i;l++)
                            F[i][j][k]=max(F[i][j][k],
                                    F[l][l][k-1]+sum[1][i]-sum[1][l]+sum[2][j]-sum[2][l]);
                }
        printf("%d\n",F[n][n][K]);
    }
    return 0;
}

祝各位dalao成功AC!!!