貪欲法 abc103 b atcoder

ABC103 B - Islands War

ABC103 B - Islands War
Feb. 2, 2020, 1:52 p.m.

目次

問題

https://atcoder.jp/contests/abc103/tasks/abc103_d

入力

N M
a_1 b_1
a_2 b_2
...
a_M b_M
  • N - 島の数
  • M - 切り離す島の組み合わせの数
  • a_i b_i - a_i番目とb_i番目の島を切り離す必要がある

出力

C

$N$個の島が横一列に橋で繋がっていてお互いに行き来出来るようになっています.
$M$個の島の組み合わせをお互いに行き来出来ないようにするには最小でいくつの橋を壊せば十分かを答える問題です.

入出力例

9 5
1 8
2 7
3 5
4 6
7 9
2

イメージ図です. #が左の島、xが右の島です. |が切断ポイントです.
2箇所切断すれば十分なことが分かります.

1 2 3 4 5 6 7 8 9
#      |      x
  #    |    x
    #  |x
      #|  x
            #  |x

解説

もう1つサンプルのイメージ図2です.

1 2 3 4 5
#|x
#|  x
#|    x
#|      x
  #|x
  #|  x
  #|    x
    #|x
    #|  x
      #|x

これら2つの図を参考にしつつ問題の性質をよく考えます.
まずは島の組み合わせの#x#のインデックスが小さい順にソートしてみます.
そして最初の組み合わせについてxの手前に切断点を置いてみます. 12の間です.
次に2番目の組み合わせを見ると、#の位置は変わらずxが遠くなっています.
切断点を後ろにずらすと最初の組み合わせが切断できなくなってしまうので切断点はステイです(動かしません).
それを4つ目まで繰り返します.
5つ目。
#が切断点よりも遠くに来てしまいました.
最初の組み合わせと5つ目の組み合わせを両方とも満たせる切断点は無いのでもう1つ新しい切断点を追加します.
あとはこの処理をすべての組み合わせについて繰り返します.

最終的な切断点の数が答えになります.

計算量

貪欲法的にすべての組み合わせ$M$個にいて1度ずつ計算します.

$$O(M)$$

解答

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#define MAX_M 100000

struct Island {
  Int start, end;
  Island() {}
  Island(Int s, Int e): start(s), end(e) {}
  bool operator < (const Island &v) const {
    return (start == v.start) ? end < v.end : start < v.start;
  }
};

Int N, M;
vector<Island> islands;

void input() {
  cin >> N >> M;
  Int s_, e_;
  loop(m,0,M) {
    cin >> s_ >> e_;
    islands.push_back(Island(s_, e_));
  }
}

void solve() {
  sort(span_all(islands));
  Int count = 0, right = -1;
  for (auto i: islands) {
    if (right <= i.start) {
      count++;
      right = i.end;
    } else {
      right = min(right, i.end);
    }
  }
  cout << count << endl;
}

int main() {
  input();
  solve();
  return 0;
}