HDU5492 小奇的矩阵(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。
解题思路
DP.
枚举的是路径和,不容易想到.
70分:
枚举路径和,设f[s][i][j],s是和.
保证当前路径Ai和==S.
可得:
f(s,i,j)=min{f(s-a[i][j],i,j-1),f(s-a[i][j],i-1,j)}+(av-a[i][j])^2
100分:
其实不用考虑当前枚举的路径和能否满足那个跑的路径和.
因为只有是那个路径时才会得到属于他的最优解.针对每个路径,肯定只有唯一的和才能得到它的最优解.
把式子写下来再展开,就很容易证明.
所以设f[i][j]是到第i行,第j列的最小的值.
参考代码
#include<bits/stdc++.h>
#define re register
using namespace std;
typedef long long ll;
const double eps=1e-7;
const int INF=1e9;
const int N=50;
const int Max=1800;
int T;
int n,m;
double res;
double f[N][N];
int kano[N][N];
inline double Pow(double x) {
return x*x;
}
inline void Kano(int k) {
for(int i=1; i<=n; ++i)
for(int j=1; j<=m; ++j) {
f[i][j]=INF;
}
double Aavg=double(k)/(n+m-1);
f[1][1]=Pow(kano[1][1]-Aavg);
for(int i=1; i<=n; ++i)
for(int j=1; j<=m; ++j) {
if(f[i][j]!=INF) {
int x=i+1,y=j;
f[x][y]=min(f[x][y],f[i][j]+Pow(kano[x][y]-Aavg));
x=i,y=j+1;
f[x][y]=min(f[x][y],f[i][j]+Pow(kano[x][y]-Aavg));
}
}
res=min(res,f[n][m]);
}
int main(){
int tim=0;
scanf("%d",&T);
while(T--){
tim++;
res=INF;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j){
scanf("%d",&kano[i][j]);
}
for(int i=1;i<=Max;++i) Kano(i);
printf("Case #%d: %d\n",tim,int(res*(n+m-1)+1e-5));
}
}
作者:${\color{Violet}かの}$
-----若转载请附原作者名及原文链接-----
-----若转载请附原作者名及原文链接-----

浙公网安备 33010602011771号