1. 程式人生 > >備戰Noip2018模擬賽11(B組)T4 Path 好路線

備戰Noip2018模擬賽11(B組)T4 Path 好路線

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,平均值則\酒吧{X}

定義為                                                \ bar {x} = \ frac {x_ {1} + x_ {2} + ... + x_ {k}} {k}

方差\ sigma ^ {2}的定義為

                              \ sigma ^ {2} = \ frac {\ left(x_ {1}  -  \ bar {x} \ right)^ {2} + \ left(x_ {2}  -  \ bar {x} \ right)^ {2 } + ... + \ left(x_ {k}  -  \ bar {x} \ right)^ {2}} {k}

本題為了方便,只需輸出\ left(n + m  -  1 \ right)^ {2} * \ sigma ^ {2}的值就可以了

輸入格式

第一行輸入兩個整數N,M,表示城市的大小。

接下來Ñ行,每行米個數,其中第X行第ý個數就是H(X,Y)。

輸出格式

輸出一行一個整數,表示\ left(n + m  -  1 \ right)^ {2} * \ sigma ^ {2}的最小值。

輸入樣例

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;
}