1. 程式人生 > >【題解】ZJOI2013螞蟻尋路

【題解】ZJOI2013螞蟻尋路

std 復雜 clas printf while void nbsp 另一個 數組

  這題強呀……打了10+30暴力之後苦想1h並不會做……於是去看題解。看題解的時候又莫名各種看錯,結果看了好久才懂……記錄一下血淚史吧。

  這題不難發現走出來的圖形就是一個高低高低的城堡型圖案,命名為高峰跟低谷的話就是一共有k個低谷和k + 1個高峰,且交替出現。發現其實這個圖形是由2 * k + 1個矩形所構成的,我們考慮將這樣許多矩形看做轉移的方向:f[i][j][p][h]代表以點(i, j)為左下角,當前枚舉到的是第p個矩形,且高度為(i - h + 1)所能獲得的最大權值。

  轉移方程:

    \(f[i][j][p][h] = \left \{ f[i][j - 1][p][h], f[i][j - 1][p][h‘]] \right \} + s[j][i] - s[j][h - 1]; \)

  其中第一部分代表和j - 1處於同一個矩形當中,第二部分則表示根據p的奇偶性選擇<h或>h的轉移。第二部分如果枚舉,則復雜度太高了難以承受,所以用另一個數組g來保存,追加一維0/1來表示是>還是<中的最大值。期間有一個讓我比較糾結的地方,就是

    \( ans = max(f[i][j][k][i], g[i][j][k][i][0]); \)

  然後發現其實 i 這一維是沒有參與轉移的,所以將這一維去掉,節約空間。

  起初並沒有很理解為什麽要將前一部分考慮進來。當高度等於i,不是說明這是一個低谷嗎?為什麽會符合條件呢?但其實有一種情況下是可以的:當沒有低谷的時候,這樣是一個符合條件的解。2d的dp做的太少了,要多多加油呀ヾ(????)?"

#include <bits/stdc++.h>
using namespace std;
#define INF 999999999
#define maxn 105
int n, m, k, ans = -INF, sum[maxn][maxn];
int f[maxn][maxn][maxn], g[maxn][maxn][maxn][2];

int read()
{
    int x = 0, k = 1;
    char c;
    c = getchar();
    while(c < 0 || c > 9) { if(c == -) k = -1
; c = getchar(); } while(c >= 0 && c <= 9) x = x * 10 + c - 0, c = getchar(); return x * k; } void work() { for(int p = 1; p <= k; p ++) for(int h = 1; h <= n; h ++) { f[0][p][h] = -INF; g[0][p][h][0] = g[0][p][h][1] = -INF; } for(int i = 1; i <= n; i ++) for(int j = 1; j <= m; j ++) { for(int p = 1; p <= k; p ++) { for(int h = 1; h <= i; h ++) { f[j][p][h] = max(f[j - 1][p][h], g[j - 1][p - 1][h][p % 2]); f[j][p][h] += sum[j][i] - sum[j][h - 1]; } g[j][p][1][0] = -INF; for(int h = 2; h <= i; h ++) g[j][p][h][0] = max(g[j][p][h - 1][0], f[j][p][h - 1]); g[j][p][i][1] = -INF; for(int h = i - 1; h >= 1; h --) g[j][p][h][1] = max(g[j][p][h + 1][1], f[j][p][h + 1]); } ans = max(ans, max(f[j][k][i], g[j][k][i][0])); } } int main() { n = read(), m = read(), k = read(); k = k * 2 + 1; for(int i = 1; i <= n; i ++) for(int j = 1; j <= m; j ++) { int t = read(); sum[j][i] += sum[j][i - 1] + t; } work(); printf("%d\n", ans); return 0; }

【題解】ZJOI2013螞蟻尋路