10月27日备战Noip2018模拟赛11(B组)
T4路径好路线
题目描述
nodgd在旅游。现在,nodgd要从城市的西北角走到东南角去。这个城市的道路并不平坦,nodgd希望找出一条相对比较好走的路
.nodgd事先已经得到了这个城市的地图。地图上这个城市是一个nxm的矩形,nodgd现在站在坐标为(1,1)的位置,需要到达坐标为(n,m)的位置。这张地图上用非负整数标记了每个整数坐标点的海拔,坐标为(x,y)的位置的海拔是h(x,y).nodgd希望找出一条路线,路线中任意时刻都在向正东或向正南走,而且只在整数坐标点的地方转弯,使得路上经过的n + m -1个整数坐标点的海拔的方差最小。然而万能的nodgd当然知道该怎么走,也当然知道方差最小是多少,只是想顺便考考你。假如
有ķ个实数X1,X2,...,XK,平均值则定义为
方差
的定义为
本题为了方便,只需输出
的值就可以了
输入格式
第一行输入两个整数N,M,表示城市的大小。
接下来Ñ行,每行米个数,其中第X行第ý个数就是H(X,Y)。
输出格式
输出一行一个整数,表示
的最小值。
输入样例
2 2
1 2
3 4
输出样例
14
样例解释
有两条路1-2-4和1-3-4,方差都等于14/9,所以方差最小值是14/9,输出14。
数据范围
对于30%的数据,1≤n,m≤10;
对于50%的数据,1≤n,m≤20;
对于100%的数据,1≤n,m≤50,0≤h(X,Y)≤50
思路
DP
dp [i] [j] [k]表示在第i行,第j列,海拔和为k的海拔的平方的最大和
dp [i] [j] [k] = min(dp [i] [j - 1] [k - h [i] [j]],dp [i - 1] [j] [k - h [i] [j]])+ h [i] [j] * h [i] [j];
至于平方和和方差之间的关系,稍微算一算就十分显然了。
代码
#include <iostream>
#include <cstdio>
using namespace std;
const int MAXN = 55;
const int MAXS = 5005;
const int INF = 0x3fffffff;
int n, m, tmp, last;
int dp[MAXN][MAXN][MAXS];
int h[MAXN][MAXN], Max[MAXN][MAXN], Min[MAXN][MAXN];
long long ans;
inline int read ();
int main ()
{
freopen("path.in", "r", stdin);
freopen("path.out", "w", stdout);
n = read (), m = read ();
for (int i = 1; i <= n; ++ i){
for (int j = 1; j <= m; ++ j){
h[i][j] = read ();
Max[i][j] = max (Max[i - 1][j], Max[i][j - 1]) + h[i][j];
Min[i][j] = min (Min[i - 1][j], Min[i][j - 1]) + h[i][j];
}
}
for (int i = 0; i <= n; ++ i){
for (int k = 0; k <= Max[n][m]; ++ k){
dp[i][0][k] = INF;
}
}
for (int j = 0; j <= m; ++ j){
for (int k = 0; k <= Max[n][m]; ++ k){
dp[0][j][k] = INF;
}
}
dp[0][1][0] = 0;
dp[1][0][0] = 0;
ans = 9223372036854775800;
for (int i = 1; i <= n; ++ i){
for (int j = 1; j <= m; ++ j){
tmp = h[i][j] * h[i][j];
for (int k = 0; k < Min[i][j]; ++ k){
dp[i][j][k] = INF;
}
for (int k = Max[i][j] + 1; k <= Max[n][m]; ++ k){
dp[i][j][k] = INF;
}
for (int k = Min[i][j]; k <= Max[i][j]; ++ k){
last = k - h[i][j];
dp[i][j][k] = min (dp[i - 1][j][last], dp[i][j - 1][last]) + tmp;
}
}
}
for (int k = Min[n][m]; k <= Max[n][m]; ++ k){
//printf ("ans = %d, k = %d\n", ans, k);
//printf ("dp[n][m][k] = %d\n", dp[n][m][k]);
ans = min (ans, 1ll * dp[n][m][k] * (n + m - 1) - 1ll * k * k);
}
printf ("%d", ans);
fclose(stdin);
fclose(stdout);
return 0;
}
inline int read ()
{
char ch = getchar ();
while (!isdigit (ch)) ch = getchar ();
int x = 0;
while (isdigit (ch)) {
x = x * 10 + ch - '0';
ch = getchar ();
}
return x;
}