Problem : A | B | C | D | E | F | G | H

C - Anti Rudal

Data rudal yang diberikan bisa kita representasikan ke dalam koordinat kartesian dengan t-waktu sebagai absis (sumbu-x) dan h-ketinggian sebagai ordinat (sumbu-y). Dengan demikian, yang perlu kita cari adalah berapa jumlah minimal garis yang diperlukan agar semua titik tercover.

Soal ini mirip dengan UVA 497 - Strategic Defense Initiative dengan inti permasalahan yang berbeda, di mana kita diminta untuk mencari berapa jumlah maksimal rudal yang bisa dijatuhkan jika kita hanya memiliki satu peluncur anti-rudal. Permasalahan tersebut adalah salah satu problem klasik Longest Increasing Subsequence (LIS) yang bisa diselesaikan dengan dynamic programming.

Gagasan yang mungkin muncul pertama kali ketika mengerjakan soal ini adalah dengan melakukan LIS berulang-ulang sampai semua titik tercover, namun sayangnya pendekatan ini tidak menghasilkan solusi yang optimal (lihat gambar di bawah).


posisi semua rudal

solusi LIS berulang, output = 3

solusi optimal, output = 2

Untuk menyelesaikan soal ini, urutkan semua titik yang diberikan dari h terkecil ke terbesar. Untuk titik dengan h yang sama, urutkan berdasarkan t terkecil dahulu. Gambar garis pertama dengan mengambil titik pertama yang bisa diambil (sesuai urutan). Ulangi lagi dengan menggambar garis berikut hingga semua titik tercover.

Alternatif lain adalah dengan mengurutkan semua titik dari t terkecil hingga terbesar, namun untuk t yang sama harus diurutkan berdasarkan h terbesar.


Statistik Problem C
YES = 2
NO - Wrong Answer = 18
NO - Time Limit Exceeded = 0
NO - Run-time Error = 3
NO - Compile Error = 1


Solusi C/C++   (oleh Suhendry Effendy)
#include <cstdio>
#include <algorithm>
using namespace std;

const int maxn = 105;

int main()
{

  int T;
  scanf( "%d", &T );

  while ( T-- ) {
    int N;
    int t[maxn];
    int h[maxn];

    scanf( "%d", &N );
    for ( int i = 0; i < N; i++ ) scanf( "%d", &t[i] );
    for ( int i = 0; i < N; i++ ) scanf( "%d", &h[i] );
    
    for ( int i = 0; i < N; i++ )
      for ( int j = i; j < N; j++ )
        if ( h[i] > h[j] || (h[i] == h[j] && t[i] > t[j]) ) {
          swap(t[i], t[j]);
          swap(h[i], h[j]);
        }
    
    int  ans = 0;
    bool clear = false;
    bool shot[maxn] = {false};

    while ( !clear ) {
      clear = true;
      int last = -1;
      for ( int i = 0; i < N; i++ ) {
        if ( !shot[i] && t[i] > last ) {
          clear = false;
          shot[i] = true;
          last = t[i];
        }
      }
      if ( !clear ) ans++;
    }
    
    printf( "%d\n", ans );
  }

  return 0;
}
Solusi Pascal   (oleh Eko Wibowo)
var
  i, j, n, tcase, last, ans :longint;
  h,t   : array[1..100] of longint;
  clear : boolean;
  shot  : array[1..100] of boolean;
procedure swap(var a, b : longint);
var c : longint;
begin
  c := a;
  a := b;
  b := c;
end;

begin
  read(tcase);
  while (tcase > 0) do
  begin
    tcase := tcase - 1;
    read(n);
    for i := 1 to n do read(t[i]);
    for i := 1 to n do read(h[i]);
    for i := 1 to n-1 do
      for j := i+1 to n do
        if ((h[i] > h[j]) or ((h[i] = h[j]) and (t[i] > t[j]))) then
        begin
          swap(h[i],h[j]);
          swap(t[i],t[j]);
        end;
    ans:=0;
    for i := 1 to n do shot[i] := false;
    clear := false;
    while not clear do
    begin
      clear := true;
      last  := -1;
      for i:=1 to n do
        if (not shot[i] and (t[i] > last)) then
        begin
          clear :=false;
          shot[i] :=true;
          last :=t[i];
        end;
      if not clear then ans := ans + 1;
    end;
    writeln(ans);
  end;
end.