結果

問題 No.114 遠い未来
ユーザー te-shte-sh
提出日時 2017-08-09 10:56:02
言語 D
(dmd 2.106.1)
結果
TLE  
実行時間 -
コード長 3,925 bytes
コンパイル時間 819 ms
コンパイル使用メモリ 110,772 KB
実行使用メモリ 10,612 KB
最終ジャッジ日時 2023-09-03 15:39:09
合計ジャッジ時間 17,348 ms
ジャッジサーバーID
(参考情報)
judge12 / judge11
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 261 ms
8,880 KB
testcase_01 TLE -
testcase_02 AC 531 ms
4,380 KB
testcase_03 AC 120 ms
4,376 KB
testcase_04 AC 1 ms
4,380 KB
testcase_05 AC 19 ms
4,380 KB
testcase_06 AC 1,795 ms
4,376 KB
testcase_07 AC 1 ms
4,380 KB
testcase_08 AC 1 ms
4,376 KB
testcase_09 AC 33 ms
4,376 KB
testcase_10 AC 1,566 ms
4,500 KB
testcase_11 TLE -
testcase_12 AC 3,477 ms
4,736 KB
testcase_13 TLE -
testcase_14 -- -
testcase_15 -- -
testcase_16 -- -
testcase_17 -- -
testcase_18 -- -
testcase_19 -- -
testcase_20 -- -
testcase_21 -- -
testcase_22 -- -
testcase_23 -- -
testcase_24 -- -
testcase_25 -- -
testcase_26 -- -
testcase_27 -- -
権限があれば一括ダウンロードができます

ソースコード

diff #

import std.algorithm, std.conv, std.range, std.stdio, std.string;

alias Graph!(int, size_t) graph;

void main()
{
  auto rd1 = readln.split.to!(size_t[]), n = rd1[0], m = rd1[1], t = rd1[2];
  auto e = new Edge[](m);
  foreach (i; 0..m) {
    auto rd2 = readln.splitter;
    auto src = rd2.front.to!size_t-1; rd2.popFront();
    auto dst = rd2.front.to!size_t-1; rd2.popFront();
    e[i] = Edge(src, dst, rd2.front.to!int);
  }
  auto v = t.iota.map!(_ => readln.chomp.to!size_t-1).array;
  v.sort();

  auto calc1()
  {
    auto g = new int[][](n, n);
    foreach (ref r; g) r[] = graph.inf;
    foreach (i; 0..n) g[i][i] = 0;

    foreach (ref ei; e) g[ei.s][ei.t] = g[ei.t][ei.s] = ei.w;
    auto r = graph.minimumSteinerTree(v, g);
    return r >= graph.inf ? 0 : r;
  }

  auto calc2()
  {
    auto cb = ulong(0);
    foreach (vi; v) cb = cb.bitSet(vi);
    
    auto w = n.iota.setDifference(v).array;
    e.sort!"a.w < b.w";

    auto u = n - t, ans = int.max, checked = new bool[](1<<u);
    foreach (i; 0..1<<u) {
      auto cc = cb;
      foreach (j; 0..u)
        if (i.bitTest(j)) cc = cc.bitSet(w[j]);

      auto ec = e.filter!(ei => cc.bitTest(ei.s) && cc.bitTest(ei.t));
      auto uf = UnionFind!size_t(n), r = 0;

      auto check()
      {
        auto c = n;
        foreach (i; 0..n)
          if (cc.bitTest(i)) {
            auto d = uf.find(i);
            if (c != n && c != d) return false;
            c = d;
          }
        return true;
      }

      foreach (eci; ec) {
        if (!uf.isSame(eci.s, eci.t)) {
          uf.unite(eci.s, eci.t);
          r += eci.w;
        }
      }

      auto c = i ? checked[i.bitReset(i.bsf)] : false;
      if (!c) c = checked[i] = check;
      if (c) ans = min(ans, r);
    }

    return ans;
  }

  writeln(t <= 14 ? calc1 : calc2);
}

pragma(inline) {
  pure bool bitTest(T)(T n, size_t i) { return (n & (T(1) << i)) != 0; }
  pure T bitSet(T)(T n, size_t i) { return n | (T(1) << i); }
  pure T bitReset(T)(T n, size_t i) { return n & ~(T(1) << i); }
  pure T bitComp(T)(T n, size_t i) { return n ^ (T(1) << i); }

  import core.bitop;
  pure int bsf(T)(T n) { return core.bitop.bsf(ulong(n)); }
  pure int bsr(T)(T n) { return core.bitop.bsr(ulong(n)); }
  pure int popcnt(T)(T n) { return core.bitop.popcnt(ulong(n)); }
}

struct Edge { size_t s, t; int w; }

template Graph(Wt, Node, Wt _inf = 10 ^^ 9)
{
  import std.algorithm, std.array;

  const inf = _inf;

  Wt minimumSteinerTree(Node[] t, Wt[][] g)
  {
    auto n = g.length, nt = t.length;
    auto d = g.map!(i => i.dup).array;

    foreach (k; 0..n)
      foreach (i; 0..n)
        foreach (j; 0..n)
          d[i][j] = min(d[i][j], d[i][k] + d[k][j]);

    auto opt = new Wt[][](1<<nt, n);
    foreach (s; 0..1<<nt)
      opt[s][] = inf;

    foreach (p; 0..nt)
      foreach (q; 0..n)
        opt[1<<p][q] = d[t[p]][q];

    foreach (s; 1..1<<nt)
      if (s & (s-1)) {
        foreach (p; 0..n)
          foreach (e; 0..s)
            if ((e | s) == s) opt[s][p] = min(opt[s][p], opt[e][p] + opt[s-e][p]);
        foreach (p; 0..n)
          foreach (q; 0..n)
            opt[s][p] = min(opt[s][p], opt[s][q] + d[p][q]);
      }

    Wt ans = inf;
    foreach (s; 0..1<<nt)
      foreach (q; 0..n)
        ans = min(ans, opt[s][q] + opt[$-1-s][q]);

    return ans;
  }
}

struct UnionFind(T)
{
  import std.algorithm, std.range;

  T[] p; // parent
  const T s; // sentinel
  const T n;

  this(T n)
  {
    this.n = n;
    p = new T[](n);
    s = n + 1;
    p[] = s;
  }

  T find(T i)
  {
    if (p[i] == s) {
      return i;
    } else {
      p[i] = find(p[i]);
      return p[i];
    }
  }

  void unite(T i, T j)
  {
    auto pi = find(i), pj = find(j);
    if (pi != pj) p[pj] = pi;
  }

  bool isSame(T i, T j) { return find(i) == find(j); }

  auto groups()
  {
    auto g = new T[][](n);
    foreach (i; 0..n) g[find(i)] ~= i;
    return g.filter!(l => !l.empty);
  }
}
0