ABC103 B - Islands War

Calendar Clock iconCalendar Clock icon

atcoder

目次

# 問題

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

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

# 入出力例

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つ新しい切断点を追加します.
あとはこの処理をすべての組み合わせについて繰り返します.

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

# 計算量

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

O(M)O(M)

# 解答

// C++ 14
#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <algorithm>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <unordered_map>
#include <math.h>

#define ll long long
#define Int int
#define loop(x, start, end) for(Int x = start; x < end; x++)
#define loopdown(x, start, end) for(int x = start; x > end; x--)
#define rep(n) for(int x = 0; x < n; x++)
#define span(a,x,y) a.begin()+x,a.begin()+y
#define span_all(a) a.begin(),a.end()
#define len(x) (x.size())
#define last(x) (*(x.end()-1))

using namespace std;
#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;
}

リモートフリーランス。ウェブサービス、スマホアプリエンジニア。
東アジアを拠点に世界を移動しながら活動してます!

お仕事のご依頼・お問い合わせはこちら

コメント