1. 程式人生 > >2015 ACM/ICPC Asia Regional Hefei Online I - Find a path(推公式+dp)

2015 ACM/ICPC Asia Regional Hefei Online I - Find a path(推公式+dp)

題目連結傳送門

 

題意:在n*m的平面上,每個點都具有貢獻,問你從(1,1)到(n,m)找到一條路徑(只能往上或者往右),使得路徑上的點的方差最小。詢問最小的方差值為多少。

 

解決方法:首先根據簡化所給公式可以推出一個式子。推出式子的步驟如下

公式遞推很簡單。可以忽略。

下一步我們就可以用一個dp[i][j][k]來表示走到(i,j)時序列和為k(序列和不會超過(30+30-1)*30)時的平方和最小值,注意一下dp陣列的初始化,然後暴力更新就行了。

向上的方程:dp[i + 1][z][k + ax[i + 1][z]] = min(dp[i + 1][z][k + ax[i + 1][z]], dp[i][z][k] + ax[i + 1][z] * ax[i + 1][z]);

向右的方程:dp[i][z + 1][k + ax[i][z + 1]] = min(dp[i][z + 1][k + ax[i][z + 1]], dp[i][z][k] + ax[i][z + 1] * ax[i][z + 1]);

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<iostream>
#include<map>
#include<vector>
#include<set>
#include<queue>
using namespace std;
const int inf = 0x3f3f3f3f;
typedef long long ll;
int ax[50][50];
ll dp[50][50][2000];
int main(void) {
	int t;
	scanf("%d", &t);
	int zzz = 1;
	while (t--) {
		int n, m;
		int tot = 0;
		scanf("%d%d", &n, &m);
		int maxx = 0;
		for (int i = 1; i <= n; i++){
			for (int z = 1; z <= m; z++) {
				scanf("%d", &ax[i][z]);
				maxx = max(ax[i][z], maxx);
			}
		}
		printf("Case #%d: ", zzz++);
		for (int i = 0; i <= n; i++) {
			for (int z = 0; z <= m; z++) {
				for (int j = 0; j <= (n + m - 1)*maxx+10; j++) {
					dp[i][z][j] = inf;
				}
			}
		}
		dp[1][1][ax[1][1]] = ax[1][1] * ax[1][1];
		for(int i=1;i<=n;i++){
			for (int z = 1; z <= m; z++) {
				for (int k = 0; k <= (n + m - 1)*maxx + 10; k++) {
					if (dp[i][z][k] != inf) {
						if (i + 1 <= n) {
							dp[i + 1][z][k + ax[i + 1][z]] = min(dp[i + 1][z][k + ax[i + 1][z]], dp[i][z][k] + ax[i + 1][z] * ax[i + 1][z]);
						}
						if (z + 1 <= m) {
							dp[i][z + 1][k + ax[i][z + 1]] = min(dp[i][z + 1][k + ax[i][z + 1]], dp[i][z][k] + ax[i][z + 1] * ax[i][z + 1]);
						}
					}
				}
			}
		}
		ll ans = inf;
		for (ll i = 0; i <= (n+m-1)*maxx + 10; i++) {
			if (dp[n][m][i] != inf) {
				ans = min(ans, (n + m - 1)*dp[n][m][i] - i*i);
			}
		}
		printf("%lld\n", ans);
	}
	return 0;
}