小奇的矩阵
【问题描述】
给定一个 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
把式子化简:
ans=(n-m+1)∑Ai2-sum2
但这个式子并不是Ai越小越好
于是dp
令f[i][j][k]表示到(i,j)路径和为k,路径的平方和
于是答案就是(n-m+1)*f[n][m][i]-i2
考试时傻逼,把求和的变量忘了清0,后来直接赋为(n+m)*30
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 long long n,m; 7 long long a[35][35],f[35][35][2001],inf,s,ans; 8 long long min(long long a,long long b) 9 { 10 if (a<b) return a; 11 return b; 12 } 13 int main() 14 { 15 int T; 16 long long i,j,k; 17 cin>>T; 18 while (T--) 19 { 20 scanf("%lld%lld",&n,&m); 21 s=0; 22 for (i=1; i<=n; i++) 23 for (j=1; j<=m; j++) 24 scanf("%lld",&a[i][j]),s+=a[i][j]; 25 memset(f,127/2,sizeof(f)); 26 inf=f[0][0][0]; 27 f[1][1][a[1][1]]=a[1][1]*a[1][1]; 28 for (i=1; i<=n; i++) 29 { 30 for (j=1; j<=m; j++) 31 { 32 if (i==1&&j==1) continue; 33 for (k=0; k<=(n+m)*30; k++) 34 { 35 long long x=a[i][j]*a[i][j]; 36 if (i>1) f[i][j][k+a[i][j]]=min(f[i][j][k+a[i][j]],f[i-1][j][k]+x); 37 if (j>1) f[i][j][k+a[i][j]]=min(f[i][j][k+a[i][j]],f[i][j-1][k]+x); 38 } 39 } 40 } 41 ans=inf; 42 for (i=0; i<=(m+n)*30; i++) 43 if (f[n][m][i]!=inf) 44 ans=min(ans,f[n][m][i]*(n+m-1)-i*i); 45 cout<<ans<<endl; 46 } 47 }