bzoj[SCOI2005]最大子矩陣

描述

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

格式

輸入格式

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

輸出格式

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

樣例

樣例輸入
3 2 2
1 -3
2 3
-2 3

樣例輸出
9

限制

每個測試點1s

來源

NOI2005四川省選拔賽第二試第4題

當時的省選題,放在現在難度已經不大了。如果這道題的 m 也是 1-100 ,那麼就不好辦了,好在它最大隻有 2 = =。這個時候我們就可以分治處理,m=1 的時候怎麼處理,m=2 的時候怎麼處理,放在考場上這是個很實用的技巧,在想不出正解的時候分治處理特殊測試數據。

m=1 的情況應該很好想到,用 f[i][k] 表示這一列取到第 i 個數正好用了 k 個矩陣的最優解,就由幾個狀態轉移過來:
1、不選第 i 個數。
2、選這個數構成一個新的矩陣,也就是從 k-1 到 i-1 中不取某個數。
方程:
for(int j=i-1;j>=k-1;j–)
f[i][k]=max(f[i][k],f[j][k-1]+sum[i][1]-sum[j][1]);
爲什麼是到 k-1 呢?這是因爲狀態是有選k-1個推過來,選的數肯定是大於等於構成的矩陣的數的。

m=1 的情況搞清楚了,那麼m=2 的情況也就迎刃而解了。我們用f[i][j][k]表示第 1 列取了 i 個,第 2 列取了 j 個,正好用了 k 個矩陣,那麼這個狀態就要推兩次上面的方程,分別是第一列的和第二列的。特殊情況,如果 i==j ,那麼再推一次兩列一起的就可以了。
代碼如下:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int map[110][20],f[1100][110][20];
int sum[110][20];
int main()
{
    int n,m,k;
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            cin>>map[i][j];
            sum[i][j]=sum[i-1][j]+map[i][j];
        }
    if(m==1)
    {
        f[1][1][1]=map[1][1];
        for(int i=1;i<=n;i++)
            for(int j=1;j<=k;j++)
            {
                f[i][1][j]=f[i-1][1][j];
                for(int kk=i-1;kk>=j-1;kk--)
                    f[i][1][j]=max(f[i][1][j],f[kk][1][j-1]+sum[i][1]-sum[kk][1]);
            }
        cout<<f[n][1][k];
        return 0;
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            for(int kk=1;kk<=k;kk++)
            {
                f[i][j][kk]=max(f[i-1][j][kk],f[i][j-1][kk]);
                for(int t=i-1;t>=kk-1;t--)
                    f[i][j][kk]=max(f[i][j][kk],f[t][j][kk-1]+sum[i][1]-sum[t][1]);
                for(int t=j-1;t>=kk-1;t--)
                    f[i][j][kk]=max(f[i][j][kk],f[i][t][kk-1]+sum[j][2]-sum[t][2]);
                if(i==j)
                    for(int t=i-1;t>=kk-1;t--)
                        f[i][j][kk]=max(f[i][j][kk],f[t][t][kk-1]+sum[i][1]-sum[t][1]+sum[j][2]-sum[t][2]);
            }
    cout<<f[n][n][k];
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章