2017年11月7日提高组T2 好路线
Description
nodgd在旅游。现在,nodgd要从城市的西北角走到东南角去。这个城市的道路并不平坦,nodgd希望找出一条相对比较好走的路。
nodgd事先已经得到了这个城市的地图。地图上这个城市是一个n×m的矩形,nodgd现在站在坐标为(1,1)的位置,需要到达坐标为(n,m)的位置。这张地图上用非负整数标记了每个整数坐标点的海拔,坐标为(x,y)的位置的海拔是h(x,y)。nodgd希望找出一条路线,路线中任意时刻都在向正东或向正南走,而且只在整数坐标点的地方转弯,使得路上经过的n+m-1个整数坐标点的海拔的方差最小。然而万能的nodgd当然知道该怎么走,也当然知道方差最小是多少,只是想顺便考考你。
假如有k个实数x1,x2,…,xk,则平均值定义为
在本题中为了方便,你只需要求出(n+m-1)^2*方差的最小值即可,众所周知这是个整数。
Input
第一行输入两个整数n,m,表示城市的大小。
接下来n行,每行m个数,其中第i行第j个数就是h(i,j)。
Output
输出一行一个整数,表示(n+m-1)^2*方差的最小值。
Sample Input
2 2
1 2
3 4
Sample Output
14
Hint
对于30%的数据,1≤n,m≤10;
对于50%的数据,1≤n,m≤20;
对于100%的数据,1≤n,m≤50,0≤h(x,y)≤50。
分析:通过将该式子化简可知n*Σxi^2-(Σxi)^2
因此定义dp[i][j][k]表示到i j时总和为k的最小n*Σxi^2,最后答案减去(Σxi)^2 即可。
代码
#include <cstdio>
#define N 60
#define ll long long
using namespace std;
ll f[N][N][N*100],a[N][N],n,m;
ll fsqr(ll x)
{
return x*x;
}
ll min(ll x,ll y)
{
return x<y?x:y;
}
int main()
{
freopen("route.in","r",stdin);
freopen("route.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
scanf("%lld",&a[i][j]);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
for (int k=0;k<=(n+m-1)*50;k++)
f[i][j][k]=1e9;
f[1][1][a[1][1]]=fsqr(a[1][1]);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
for (int k=0;k<=(n+m-1)*50;k++)
{
if (f[i][j][k]==1e9) continue;
int dx,dy;
dx=i;dy=j+1;
f[dx][dy][k+a[dx][dy]]=min(f[dx][dy][k+a[dx][dy]],f[i][j][k]+fsqr(a[dx][dy]));
dx=i+1;dy=j;
f[dx][dy][k+a[dx][dy]]=min(f[dx][dy][k+a[dx][dy]],f[i][j][k]+fsqr(a[dx][dy]));
}
ll ans=1e9;
for (int i=0;i<=(n+m-1)*50;i++)
ans=min(ans,f[n][m][i]*(n+m-1)-fsqr(i));
printf("%lld",ans);
fclose(stdin);
fclose(stdout);
}