SSL2841 2017年11月7日提高组T2 好路线(dp)

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);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值