1. 程式人生 > >座標DP 小奇的矩陣(matrix)

座標DP 小奇的矩陣(matrix)

問題 B: 小奇的矩陣(matrix)
時間限制: 1 Sec 記憶體限制: 256 MB
提交: 95 解決: 34
[提交][狀態]
題目描述
【題目背景】

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

【問題描述】

給定一個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

我貌似幾個月沒打過座標DP了。。。
把那個式子化簡一下就是(n+m-1)*∑(ai^2)-(∑ai)^2
但這個式子的值在走到一半時並無法確定是不是最優。但是ai<=30,加和最大隻有1000幾,那麼把f陣列加一維,列舉當前的sigma是多少就行了。最後算一遍。O(N^2*S)

#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int read()
{
    int sum=0,f=1;char x=getchar();
    while(x<'0'||x>'9'){if(x=='-')f=-1;x=getchar();}
    while(x>='0'&&x<='9'){sum=(sum<<1
)+(sum<<3)+x-'0';x=getchar();} return sum*f; } int t,n,m,g,a[35][35],f[2005][35][35],ans; int main() { t=read(); while(t--) { memset(f,-1,sizeof(f)); n=read();m=read();g=m+n-1; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j]=read(); f[a[1][1]][1][1]=a[1][1]*a[1][1]; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) for(int k=a[i][j];k<=1500;k++) { if(i==1&&j==1)continue; if(f[k-a[i][j]][i-1][j]!=-1) f[k][i][j]=f[k-a[i][j]][i-1][j]+a[i][j]*a[i][j]; if(f[k-a[i][j]][i][j-1]!=-1) { if(f[k][i][j]==-1)f[k][i][j]=f[k-a[i][j]][i][j-1]+a[i][j]*a[i][j]; else f[k][i][j]=min(f[k][i][j],f[k-a[i][j]][i][j-1]+a[i][j]*a[i][j]); } } int ans=2000000000; for(int i=0;i<=1500;i++) { if(f[i][n][m]==-1)continue; ans=min(ans,f[i][n][m]*g-i*i); } printf("%d\n",ans); } }