小奇的矩陣 DP

小奇的矩陣

【題目背景】

小奇總是在數學課上思考奇怪的問題。

【問題描述】

給定一個n*m的矩陣,矩陣中的每個元素aij爲正整數。

接下來規定

1.合法的路徑初始從矩陣左上角出發,每次只能向右或向下走,終點爲右下角。

2.路徑經過的n+m-1個格子中的元素爲A1,A2…A(n+m-1),Aavg爲Ai的平均數,路徑的V值爲(n+m-1)*∑(Ai-Aavg) ^2

(1<=i<=n+m-1)

求V值最小的合法路徑,輸出V值即可,有多組測試數據。

輸入格式

第一行包含一個正整數T,表示數據組數。

對於每組數據:

第一行包含兩個正整數n和m,表示矩陣的行數和列數。
接下來n行,每行m個正整數aij,描述這個矩陣。

輸出格式

對於每次詢問,輸出一行一個整數表示要求的結果

樣例輸入

1
2 2
1 2
3 4

樣例輸出

14

數據規模

對於30%的數據 n<=10,m<=10

有另外40%的數據 n<=15 m<=15,矩陣中的元素不大於5

對於100%的數據 T<=5,n<=30,m<=30,矩陣中的元素不大於30


看到方差的形式也不能打出GG。

首先容易看出來是一個DP,因爲有明顯的階段性,而且很容易想到有兩維應該用來記錄位置。但是應該記錄什麼呢?是否應該加維數呢?

留給我們的突破口就只有答案的這個式子了,所以其實本題比較好想。對於題面裏的形式顯然是難以處理的,考慮對式子變形。

Ans=(n+m1)(AiAvg)2
       =(n+m1)(A2i2AvgAi+Avg2)
       =(n+m1)(A21+A22++A2n+m1)2Avg(n+m1)(A1+A2+An+m1)+(n+m1)2Avg2

不妨設Sum=A1+A2+A3++An+m1 ,那麼根據平均數的定義有Avg(n+m1)=Sum ,代入上式化簡得

Ans=(n+m1)(A21+A22++A2n+m1)2Sum2+Sum2
       =(n+m1)(A21+A22++A2n+m1)Sum2

所以現在我們只需要求出對一個給定的Sum ,求出對應最小的(A21+A22++A2n+m1) 即可。

所以定義狀態f[i][j][k] 表示當前走到(i,j) ,當前得到的總和爲k 時的最小(A21+A22++A2i+j1) 。狀態轉移方程:

f[i][j][k]=min(f[i1][j][kAij]+f[i][j1][kAij])+A2ij

要得到最終答案,枚舉(n+m1)f[n][m][k]k2 的最小值即可。


#include<stdio.h>
#include<cstring>
#include<algorithm>
using namespace std;

int N,M,Map[35][35],f[35][35][1805];
long long Ans,Tmp;

int main()
{
    int i,j,k,T;

    scanf("%d",&T);

    while(T--)
    {
        scanf("%d%d",&N,&M);

        for(i=1;i<=N;i++)
        for(j=1;j<=M;j++)
        scanf("%d",&Map[i][j]);

        for(i=0;i<=N;i++)
        for(j=0;j<=M;j++)
        for(k=0;k<=1770;k++)f[i][j][k]=1e8;

        f[1][1][Map[1][1]]=Map[1][1]*Map[1][1];

        for(i=1;i<=N;i++)
        for(j=1;j<=M;j++)
        {
            if(i==1&&j==1)continue;
            for(k=Map[i][j];k<=1770;k++)
            f[i][j][k]=min(f[i-1][j][k-Map[i][j]],f[i][j-1][k-Map[i][j]])+Map[i][j]*Map[i][j];
        }

        Ans=1e9;
        for(k=0;k<=1770;k++)
        {
            Tmp=1ll*(N+M-1)*f[N][M][k]-k*k;
            if(Ans>Tmp)Ans=Tmp;
        }

        printf("%lld\n",Ans);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章