ゆらのふなびと

競プロ, Python, C++

RUPC2016 Day2 G : Max Pig Noodle

本番でctylさんが解法を編み出し、自分が実装した問題。

問題

http://judge.u-aizu.ac.jp/onlinejudge/cdescription.jsp?cid=RitsCamp16Day2&pid=G

解法

DP。int dp[xの残量][yの残量] = このx, yで実現できる最大のブタメソの最大個数とすればよい。交換人の順序はバラバラであってもよいが、これはx, yに負の値を認めると交換人を1人目から順に見ていくだけでよくなる。最後にx, yが正の領域でブタメソの最大値を取ればOK。計算量は100 * 600 * 600で間に合う。

以下のコードでは dp[y][ブタメソ] = x としている。こうするとちょっとメモリが減る。

const int CENTER = 300;
const int INF = 999;
const int MAX_H = 601;
const int MAX_W = 301;

int dp1[MAX_H][MAX_W];
int dp2[MAX_H][MAX_W];

signed main() {
    int n;
    cin >> n;
    int x, y;
    cin >> x >> y;

    vi a(n), b(n), c(n), d(n);
    rep(i, n) {
        cin >> a[i] >> b[i] >> c[i] >> d[i];
    }

    rep(i, MAX_H) rep(j, MAX_W) {
        dp1[i][j] = -INF;
        dp2[i][j] = -INF;
    }

    dp1[y + CENTER][0] = x;

    rep(k, n) {
        rep(i, MAX_H) {
            rep(j, MAX_W) {
                if (dp1[i][j] == -INF)
                    continue;

                dp2[i][j] = max(dp2[i][j], dp1[i][j]);
                if (i + b[k] < MAX_H) {
                    dp2[i + b[k]][j] = max(dp2[i + b[k]][j], dp1[i][j] - a[k]);
                }
                if (i - c[k] >= 0) {
                    dp2[i - c[k]][j + d[k]] = max(dp2[i - c[k]][j + d[k]], dp1[i][j]);
                }
            }
        }
        rep(i, MAX_H) rep(j, MAX_W) dp1[i][j] = dp2[i][j];
    }

    int ma = 0;
    rep2(i, CENTER, MAX_H) {
        rep(j, MAX_W) {
            if (dp2[i][j] >= 0) {
                ma = max(ma, j);
            }
        }
    }

    cout << ma << endl;

}