POJ 1191 棋盤分割 (區間DP,記憶化搜索)
阿新 • • 發佈:2019-01-31
bool for ring def bsp sca printf namespace http
題面
思路:分析公式,我們可以發現平均值那一項和我們怎麽分的具體方案無關,影響答案的是每個矩陣的矩陣和的平方,由於數據很小,我們可以預處理出每個矩陣的和的平方,執行狀態轉移。
設dp[l1][r1][l2][r2][k]是矩陣l1,r1,l2,r2切割k次的最小值,我們可以枚舉是橫著切還是豎著切執行狀態轉移。
代碼:
#include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #define INF 0x3f3f3f3f using namespace std; int dp[10][10][10][10][16], sum[10][10][10][10]; bool v[10][10][10][10][16]; int a[10][10]; void init() { for (int l1 = 1; l1 <= 8; l1++) for (int r1 = 1; r1 <= 8; r1++) for (int l2 = l1; l2 <= 8; l2++) for (int r2 = r1; r2 <= 8; r2++) { int ans = 0; for (int i = l1; i <= l2; i++) for (int j = r1; j <= r2; j++) { ans += a[i][j]; } sum[l1][r1][l2][r2] = ans * ans; } } int solve(int l1, int r1, int l2, int r2, int k) { if (v[l1][r1][l2][r2][k]) return dp[l1][r1][l2][r2][k]; if (k == 1) { return dp[l1][r1][l2][r2][k] = sum[l1][r1][l2][r2]; } int ans = INF; for (int i = l1; i < l2; i++) { ans = min(ans, min(solve(l1, r1, i, r2, k - 1) + sum[i + 1][r1][l2][r2], solve(i + 1, r1, l2, r2, k - 1) + sum[l1][r1][i][r2])); } for (int i = r1; i < r2; i++) { ans = min(ans, min(solve(l1, r1, l2, i, k - 1) + sum[l1][i + 1][l2][r2], solve(l1, i + 1, l2, r2, k - 1) + sum[l1][r1][l2][i])); } v[l1][r1][l2][r2][k] = 1; return dp[l1][r1][l2][r2][k] = ans; } int main() { int n, tot = 0; scanf("%d", &n); for (int i = 1; i <= 8; i ++) { for (int j = 1; j <= 8 ; j++) { scanf("%d", &a[i][j]); tot += a[i][j]; } } init(); solve(1, 1, 8, 8, n); double ans = sqrt(dp[1][1][8][8][n] * 1.0 / n - (tot * 1.0 / n) * (tot * 1.0 / n)); printf("%.3f\n", ans); }
POJ 1191 棋盤分割 (區間DP,記憶化搜索)