結果

問題 No.114 遠い未来
ユーザー te-shte-sh
提出日時 2017-08-09 11:38:09
言語 D
(dmd 2.106.1)
結果
AC  
実行時間 3,619 ms / 5,000 ms
コード長 3,784 bytes
コンパイル時間 801 ms
コンパイル使用メモリ 110,828 KB
実行使用メモリ 4,416 KB
最終ジャッジ日時 2023-09-03 15:39:39
合計ジャッジ時間 16,796 ms
ジャッジサーバーID
(参考情報)
judge12 / judge14
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 173 ms
4,380 KB
testcase_01 AC 1,261 ms
4,380 KB
testcase_02 AC 257 ms
4,376 KB
testcase_03 AC 48 ms
4,376 KB
testcase_04 AC 2 ms
4,376 KB
testcase_05 AC 13 ms
4,376 KB
testcase_06 AC 731 ms
4,376 KB
testcase_07 AC 1 ms
4,376 KB
testcase_08 AC 2 ms
4,376 KB
testcase_09 AC 23 ms
4,376 KB
testcase_10 AC 1,020 ms
4,416 KB
testcase_11 AC 3,619 ms
4,380 KB
testcase_12 AC 1,456 ms
4,376 KB
testcase_13 AC 2,245 ms
4,380 KB
testcase_14 AC 773 ms
4,380 KB
testcase_15 AC 1,042 ms
4,376 KB
testcase_16 AC 329 ms
4,376 KB
testcase_17 AC 317 ms
4,380 KB
testcase_18 AC 341 ms
4,380 KB
testcase_19 AC 167 ms
4,380 KB
testcase_20 AC 54 ms
4,384 KB
testcase_21 AC 11 ms
4,380 KB
testcase_22 AC 12 ms
4,380 KB
testcase_23 AC 2 ms
4,380 KB
testcase_24 AC 2 ms
4,376 KB
testcase_25 AC 2 ms
4,380 KB
testcase_26 AC 2 ms
4,376 KB
testcase_27 AC 1 ms
4,376 KB
権限があれば一括ダウンロードができます

ソースコード

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;
    foreach (i; 0..1<<u) {
      auto cc = cb;
      foreach (j; 0..u)
        if (i.bitTest(j)) cc = cc.bitSet(w[j]);

      auto mif = n - cc.popcnt + 1;
      auto uf = UnionFind(n), r = 0;

      foreach (ei; e) {
        if (cc.bitTest(ei.s) && cc.bitTest(ei.t) && uf.unite(ei.s, ei.t)) {
          r += ei.w;
          if (uf.count <= mif) break;
        }
      }

      if (uf.count <= mif) ans = min(ans, r);
    }

    return ans;
  }

  writeln(t <= 13 ? 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
{
  import std.algorithm, std.range;

  size_t[] p; // parent
  const size_t s; // sentinel
  const size_t n;
  size_t count;

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

  size_t opIndex(size_t i)
  {
    if (p[i] == s) {
      return i;
    } else {
      p[i] = this[p[i]];
      return p[i];
    }
  }

  size_t find(size_t i) { return this[i]; }

  bool unite(size_t i, size_t j)
  {
    auto pi = this[i], pj = this[j];
    if (pi != pj) {
      p[pj] = pi;
      --count;
      return true;
    } else {
      return false;
    }
  }

  bool isSame(size_t i, size_t j) { return this[i] == this[j]; }

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