備戰Noip2018模擬賽11(B組)T4 Path 好路線
阿新 • • 發佈:2018-12-17
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; }