読者です 読者をやめる 読者になる 読者になる

JAG 夏合宿 2015 Day2 G: Escape

競技プログラミング AtCoder

解法

「入ったら頂点1に戻ることができずに確実に終了する点」を列挙する。逆に、これらの点以外の点は常に行き来できるので、その点数は確実に手に入る。あとは戻れない点に設定されている点数の最大値を取れば良い。

コード

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

vector<vector<int>> g;
vector<int> w;

void dfs(int v, int p, vector<bool> &end) {
  if (g[v].size() > 2) return;
  if (v == 0) return;
  end[v] = true;
  w[v] += w[p];
  w[p] = 0;
  for (int u : g[v])
    if (u != p) dfs(u, v, end);
}

int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);

  int N, M;
  cin >> N >> M;
  w.resize(N);
  for (int i = 0; i < N; ++i) cin >> w[i];

  g.resize(N);
  for (int i = 0; i < M; ++i) {
    int u, v;
    cin >> u >> v;
    u--, v--;
    g[u].push_back(v);
    g[v].push_back(u);
  }

  vector<bool> end(N, false);
  for (int i = 1; i < N; ++i) {
    if (g[i].size() == 1) {
      end[i] = true;
      dfs(g[i][0], i, end);
    }
  }

  while (true) {
    bool finished = true;
    for (int i = 1; i < N; ++i) {
      if (end[i]) continue;
      int cnt = 0;
      int parent = -1;
      for (int v : g[i]) {
        if (!end[v]) {
          cnt++;
          parent = v;
        }
      }
      if (cnt > 1) continue;

      finished = false;
      assert(cnt > 0);
      assert(parent >= 0);

      int ma = 0;
      for (int v : g[i])
        if (end[v]) {
          ma = max(ma, w[v]);
          w[v] = 0;
        }
      w[i] += ma;
      end[i] = true;
      if (g[parent].size() <= 2) dfs(parent, i, end);
    }
    if (finished) break;
  }

  ll ans = 0;
  for (int i = 0; i < N; ++i) {
    if (end[i]) continue;
    ans += w[i];
  }

  int ma = 0;
  for (int i = 0; i < N; ++i) {
    if (!end[i]) continue;
    ma = max(ma, w[i]);
  }
  cout << (ma + ans) << endl;
}