20240709

T1

NFLSOJ P3372 game

考虑对于 B 的行动,A 会采取怎样的策略。容易发现两人路线相交只会是一条线段,因此枚举这条线段在 B 走过的哪条线段上,记录从起点和终点分别走到每个位置的最大权值,就可以搞了。然后考虑对 B 的路径 dp,\(dp[i][j][0/ 1]\) 表示从 B 的起点走到 \((i, j)\),最后一步是怎么过来的 这样 A 最大的最小收益。转移枚举从上面还是右边的哪个位置过来,对这一段路径算出 A 的最优收益,与前面的 dp 值取 \(\max\) 再与当前位置取 \(\min\) 转移。最优收益可以一边枚举位置一边算。与前面的 dp 值取 \(\max\) 是因为选择从 B 走过的哪一段路上过是 A 的决策,与当前 dp 值取 \(\min\) 是因为从哪个位置过来是 B 的决策。

这个 dp 的本质实际上是对于每条路径计算权值,计算的方法是把所有经过当前线段的合并计算,然后由于这些路径走到当前点的所有方案都被算过了,它们就是同一个状态了,会一起参与之后的计算。

代码
#include <iostream>
#include <string.h>
#define int long long
using namespace std;
int a[305][305];
int p1[305][305];
int p2[305][305];
int dp[305][305][2];
int n, m;
signed main() {
    freopen("game.in", "r", stdin);
    freopen("game.out", "w", stdout);
    int tc;
    cin >> tc;
    while (tc--) {
        memset(p1, 0, sizeof p1);
        memset(p2, 0, sizeof p2);
        cin >> n >> m;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                cin >> a[i][j];
                p1[i][j] = max(p1[i - 1][j], p1[i][j - 1]) + a[i][j];
            }
        }
        for (int i = n; i; i--) {
            for (int j = m; j; j--) 
                p2[i][j] = max(p2[i + 1][j], p2[i][j + 1]) + a[i][j];
        }
        memset(dp, 63, sizeof dp);
        int mx=p1[1][m-1];
        for(int i=2;i<=n;i++) {
            dp[i][m][1] = min(dp[i][m][1], mx+p2[i+1][m]);
            mx = max(mx, p1[i][m-1]);
        }
        mx=p2[2][m];
        for(int i=m-1;i>=1;i--) {
            dp[1][i][0] = min(dp[1][i][0],mx+p1[1][i-1]);
            mx = max(mx,p2[2][i]);
        }
        for (int i = 1; i <= n; i++) {
            for (int j = m; j; j--) {
                int mxv = 0;
                for (int k = i + 1; k <= n; k++) {
                    int tmp;
                    tmp = max(mxv, max(p2[k + 1][j], p2[k][j + 1]) + p1[k - 1][j - 1]);
                    tmp = max(tmp, p1[i - 1][j] + max(p2[k][j + 1], p2[k + 1][j]));
                    dp[k][j][1] = min(dp[k][j][1], max(dp[i][j][0], tmp));
                    mxv = max(mxv, p2[k][j + 1] + p1[k][j - 1]);
                }
                mxv = 0;
                for (int k = j - 1; k; k--) {
                    int tmp;
                    tmp = max(mxv, max(p1[i - 1][k], p1[i][k - 1]) + p2[i + 1][k + 1]);
                    tmp = max(tmp, p2[i][j + 1] + max(p1[i - 1][k], p1[i][k - 1]));
                    dp[i][k][0] = min(dp[i][k][0], max(dp[i][j][1], tmp));
                    mxv = max(mxv, p2[i + 1][k] + p1[i - 1][k]);
                }
            }
        }
        cout << min(dp[n][1][0], dp[n][1][1]) << "\n";
    }
    return 0;
}
posted @ 2024-07-14 18:46  forgotmyhandle  阅读(25)  评论(0)    收藏  举报