mayoko’s diary

プロコンとかいろいろ。

SRM 670 div1 med:Treestrat

これ本番出てたら「あぁ med やっておけば良かった…」とかなりそう(easy はわからなかったけどこっちは考えたらわかったので)。

解法

B さんは, A さんのどれかのトークンに狙いを定めてそれを集中狙いするのが得です。よって, A さんのトークンそれぞれに対して B さんが勝つためには何回移動すべきなのかを計算し, その最小値が答えになるわけです。
一方で A さんはそれぞれのトークン a がなるべくターンを稼げるようにしたいです。そのために, 「a が最終的にどの頂点にいるか」というので場合分けをして, 生き残るターン数が多いものを採用すれば良いです。

頂点 i に a が向かうとすると, a は i に向かう時寄り道する必要は無いです。その最短経路までに B のいずれかのトークンが邪魔出来てしまうと i にたどり着くことが出来ないことになります。たどり着くことができる場合は, B のいずれかのトークンがそこにたどり着くまでに何ターンかかるかを計算し, その最大値を求めます。

…とかやりましたがとーらすさんの解法のほうがスッキリしてますね…torus711.hatenablog.com

vector<vi> G;
vector<vi> d;
const int INF = 1e9;

class Treestrat {
public:
    int roundcnt(vector <int> tree, vector <int> A, vector <int> B) {
        int n = tree.size() + 1;
        G.resize(n);
        d.resize(n);
        for (int i = 0; i < n; i++) {
            d[i].resize(n);
            for (int j = 0; j < n; j++) d[i][j] = INF;
        }
        for (int i = 1; i < n; i++) {
            G[i].push_back(tree[i-1]);
            G[tree[i-1]].push_back(i);
            d[i][tree[i-1]] = d[tree[i-1]][i] = 1;
        }
        for (int i = 0; i < n; i++) d[i][i] = 0;
        int ret = INF;
        for (int k = 0; k < n; k++) for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) {
            d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
        }
        for (int a : A) {
            int maxi = 0;
            for (int i = 0; i < n; i++) {
                vector<int> path;
                int cur = a;
                path.push_back(a);
                while (cur != i) {
                    for (int v : G[cur]) {
                        if (d[a][v] == d[a][cur]+1 && d[i][cur] == d[i][v]+1) {
                            cur = v;
                            break;
                        }
                    }
                    path.push_back(cur);
                }
                bool ng = false;
                for (int v : path) {
                    for (int b : B) {
                        if (d[b][v] <= d[a][v]) {
                            ng = true;
                            break;
                        }
                    }
                }
                if (!ng) {
                    int mini = INF;
                    for (int b : B) mini = min(mini, d[b][i]);
                    maxi = max(maxi, mini);
                }
            }
            ret = min(ret, maxi);
        }
        return ret;
    }
};