NOIP2017模拟赛 好线路(dp)

问题描述

nodgd在旅游。现在,nodgd要从城市的西北角走到东南角去。这个城市的道路并不平坦,nodgd希望找出一条相对比较好走的路。
nodgd事先已经得到了这个城市的地图。地图上这个城市是一个n×m的矩形,nodgd现在站在坐标为(1,1)的位置,需要到达坐标为(n,m)的位置。这张地图上用非负整数标记了每个整数坐标点的海拔,坐标为(x,y)的位置的海拔是ℎ(x,y)。nodgd希望找出一条路线,路线中任意时刻都在向正东或向正南走,而且只在整数坐标点的地方转弯,使得路上经过的n+m−1个整数坐标点的海拔的方差最小。然而万能的nodgd当然知道该怎么走,也当然知道方差最小是多少,只是想顺便考考你。
假如有��个实数��1,��2,…,����,则平均值��̅定义为
x1+x2+…+xk
��̅=————–
k
方差σ2定义为
(x1-��̅)2+(x2-��̅)2+…+(xk-��̅)2
σ2=—————————-
k
在本题中为了方便,你只需要求出(n+m−1)2×σ2的最小值即可,众所周知这是个整数。

输入格式

//输入文件C.in。
第一行输入两个整数n,m,表示城市的大小。
接下来n行,每行m个数,其中第x行第y个数就是ℎ(x,y)。

输出格式

//输出文件C.out。
输出一行一个整数,表示(n+m−1)2×σ2的最小值。

题解

通过将该式子化简可知n*segA^2-(segA)^2
因此定义dp[i][j][k]表示到i j时总和为k的最小n*segA^2

代码

#include<stdio.h>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<iostream>
#include<queue>
#include<cstdio>
using namespace std;
#define maxn 52
#define int long long
#define inf 1e9
int dp[maxn][maxn][5101];
int g[maxn][maxn][5101]; 
int n,m,maxx;
int d[maxn][maxn];
main()
{
    int i,j,k;
    scanf("%lld%lld",&n,&m);
    for(i=1;i<=n;i++){
        for(j=1;j<=m;j++){
            scanf("%lld",&d[i][j]);
           maxx=max(maxx,d[i][j]);
        }
    }
    for(i=1;i<=n;i++)
      for(j=1;j<=m;j++)
       for(k=0;k<=maxx*(n+m-1);k++)
         dp[i][j][k]=inf;

    dp[1][1][d[1][1]]=d[1][1]*d[1][1];
    for(i=1;i<=n;i++){
        for(j=1;j<=m;j++){
            for(k=0;k<=maxx*(n+m-1);k++){
                if(dp[i][j][k]==inf) continue;
                int dx,dy,t=d[i][j];
                dx=i+1;dy=j;
                dp[dx][dy][k+d[dx][dy]]=min(dp[dx][dy][k+d[dx][dy]],dp[i][j][k]+d[dx][dy]*d[dx][dy]);
                dx=i;dy=j+1;
                dp[dx][dy][k+d[dx][dy]]=min(dp[dx][dy][k+d[dx][dy]],dp[i][j][k]+d[dx][dy]*d[dx][dy]);
            }
//          cout<<dp[i][j][3];
        }
    }

    int minn=1e9;
//     for(i=1;i<=maxx*(n+m-1);i++) cout<<dp[n][m][i]<<" ";
    for(i=1;i<=maxx*(n+m-1);i++) if(dp[n][m][i]!=inf)minn=min(minn,(n+m-1)*dp[n][m][i]-i*i);
    cout<<minn;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值