TAKMIČENJA IZ PROGRAMIRANJA


Sva pitanja, predloge ili primedbe u vezi sa takmičenjima iz programiranja možete slati na e-mail:

tak.prog@gmail.com

U toku perioda za žalbe, sve žalbe možete slati na ovaj isti e-mail.

nishtel.cpp    2,725 b      izvorni kod rešenja
nishtel.pas    3,369 b      izvorni kod rešenja
nishtel.tests.rar    3,890,102 b      test primeri
nishtel.solution.pdf    110,167 b      rešenja problema

zadatak: NishTel

Kompanija NishT el trenutno ugrađuje širom zemlje svoj najnoviji hit - brze jednosmerne međugradske telefnoske linije. Do sada su napravili m jednosmernih linija između nekih od n gradova. Svaka linija povezuje neka dva grada i ukoliko postoji linija od grada A do grada B, tada je preko nje moguće iz grada A zvati grad B ali ne i obratno (to je jedna od mana sistema ali linije su mnogo jeftinije od starih, a to je ono što je bitno). Svaku jednosmernu telefonsku liniju karakteriše jedan broj ti - vreme (u mikrosekundama) potrebno da se uspostavi veza između odgovarajućih gradova.
Grad A može da zove grad B i indirektno, ako postoji neki niz gradova, gde je A prvi, a B poslednji, i između svaka dva uzastopna grada postoji telefonska linija u odgovarajućem smeru. Tada je vreme za uspostavljanje veze između A i B jednako zbiru vremena za uspostavlja nje svih međuveza na putu. Ukoliko postoji više načina da se uspostavi veza između neka dva grada, operateri uvek biraju onaj kod koga je vreme uspostavljanja minimalno.

Poznato je da NishTel ima centre u dva grada (NishB i ABNish) kao i da je iz svakog od ta dva grada moguće zvati (direktno ili indirektno) bilo koji drugi grad. Takođe je poznato da je NishTel zapao u dugove i da mora da sruši neke od m linija koje su postavili. Oni žele da sruše što više linija ali tako da minimalna vremena potrebna za uspostavljanje veza od gradova NishB i ABNish do svakog od ostalih gradova ostanu ista (uključujući i vremena između dva centra). Pomozite NishTel-u da ispuni svoj plan i spase se stečaja.

Ulaz.

(Ulazni podaci se učitavaju iz datoteke nishtel.in.) U prvom redu ulazne datoteke nalaze se 4 prirodna broja n, m, A i B koji predstavljaju, redom, broj gradova, broj telefonskih linija i redne brojeve gradova NishB i ABNish (n ≤ 104, m ≤ 105). Gradovi su numerisani brojevima od 1 do n. U narednih m redova nalaze se po tri prirodna broja ai, bi i ti koji označavaju da postoji linija od grada ai do grada bi i da je potrebno ti mikrosekundi za uspostavljanje veze (aibi, ti ≤ 105). Između dva grada mogu postojati više telefonskih linija.

Izlaz.

(Izlazne podatke upisati u datoteku nishtel.out) U prvom i jedinom redu izlazne datoteke ispisati najveći broj telefonskih linija koje je moguće srušiti.

Primer 1.

nishtel.in      nishtel.out
4 6 1 2
1 2 1
2 1 5
2 4 1
1 4 2
1 3 3
4 3 2
2 1 4
        
2

Objašnjenje.

Rušenjem druge i četvrte telefonske linije, minimalna rastojanja od centara do ostalih gradova ostaju ista, dok je to nemoguće ako srušimo tri ili više linija.

Napomena.

U 50% test primera biće n ≤ 103.

fajl: nishtel.cpp
#include <stdlib.h>
#include <stdio.h>
#include <vector>

using namespace std;

const int inf = 2000000000;
const int MaxN = 10010;
const int MaxM = 100010;

struct edge {
  int v, w;
  edge(int _v, int _w) {
    v = _v; w = _w;
  }
};

int n, m, A, B, u, v, w, sol;
int dA[MaxN], dB[MaxN], d[MaxN];
int adj[MaxM], weight[MaxM], a[MaxM], b[MaxM], w1[MaxM];
int p[MaxN], deg[MaxN];
bool mark[MaxN];

struct Heap {
  int heap_size;
  int h[MaxN];
  int posInHeap[MaxN];

  void init(int n) { 
    heap_size = n; 
    for (int i = 1; i <= n; i++) {
      h[i] = i;
      posInHeap[i] = i;
    }
  }

  bool empty() { return (heap_size == 0); }

  void update(int u, int newVal) {
    int f, s;
    d[u] = newVal;
    s = posInHeap[u]; 
    f = s / 2;

    while (f != 0 && d[ h[f] ] > d[u]) {
      h[s] = h[f];
      posInHeap[ h[f] ] = s;
      s = f; f = s / 2;
    }
    h[s] = u;
    posInHeap[u] = s;
  }

  int extractMin() {
    int f, s, u, min;
    min = h[1];
    h[1] = u = h[heap_size--];
    f = 1;
    s = 2 * f;
    if (heap_size > s && d[ h[s + 1] ] < d[ h[s] ]) s++;

    while (s <= heap_size && d[u] > d[ h[s] ]) {
      h[f] = h[s];
      posInHeap[ h[s] ] = f;
      f = s; s = 2 * f;
      if (heap_size > s && d[ h[s + 1] ] < d[ h[s] ]) s++;
    }
    h[f] = u;
    posInHeap[u] = f;

    return min;
  }    
};

Heap H;

void Dijkstra(int START) {
  int u, v, w, min;
  for (int i = 1; i <= n; i++) d[i] = inf;
  H.init(n);
  H.update(START, 0);

  while (!H.empty()) {
    u = H.extractMin();
    for (int i = p[u]; i < p[u] + deg[u]; i++) {
      v = adj[i];
      w = weight[i];
      if (d[u] + w < d[v])
        H.update(v, d[u] + w);
    }
  }
}

int main() {

  FILE* inFile = fopen("nishtel.in", "r");
  FILE* outFile = fopen("nishtel.out", "w");

  for (int i = 1; i <= n; i++) deg[i] = 0;
  fscanf(inFile, "%d%d%d%d", &n, &m, &A, &B);
  for (int i = 1; i <= m; i++) {
    fscanf(inFile, "%d%d%d", &a[i], &b[i], &w1[i]);
    deg[a[i]]++;
  }

  p[0] = 0;
  for (int i = 1; i <= n; i++) 
    p[i] = p[i - 1] + deg[i - 1];

  for (int i = 1; i <= m; i++) { 
    adj[p[a[i]]] = b[i];
    weight[p[a[i]]] = w1[i];
        p[a[i]] = p[a[i]] + 1;
  }
    for (int i = 1; i <= n; i++)
    p[i] = p[i - 1] + deg[i - 1];
  
  Dijkstra(A);
  for (int i = 1; i <= n; i++) dA[i] = d[i];
  Dijkstra(B);
  for (int i = 1; i <= n; i++) dB[i] = d[i];

  sol = m - 2 * n + 2;
  for (int i = 1; i <= n; i++) mark[i] = false;

  for (u = 1; u <= n; u++)
    for (int i = p[u]; i < p[u] + deg[u]; i++) {
      v = adj[i];
      w = weight[i];
      if (!mark[v] && dA[v] - dA[u] == w && dB[v] - dB[u] == w) {
        mark[v] = true;
        sol++;
      }
    }
  fprintf(outFile, "%d\n", sol);

  fclose(inFile);
  fclose(outFile);
  return 0;
}
fajl: nishtel.pas
const
   MaxN = 10010;
   MaxM = 100010;
   inf = 2000000000;


var
   inFile, outFile : Text;
   n, m, A, B, u, v, w, sol, i, heap_size : longint;
   a1, b1, w1, adj, weight : array[0..MaxM] of longint;
   d, dA, dB, p, deg : array[0..MaxN] of longint;
   h, posInHeap : array[0..MaxN] of longint;
   mark : array[0..MaxN] of boolean;


procedure Input;
var
   i, u, v, w: longint;

begin

   assign( inFile, 'nishtel.in' );
   reset( inFile );
   fillchar( deg, sizeof( deg ), 0 );

   readln( inFile, n, m, A, B );
   for i := 1 to m do begin
      readln( inFile, u, v, w );
      deg[ u ] := deg[ u ] + 1;
      a1[ i ] := u; b1[ i ] := v; w1[ i ] := w;
   end;

   close( inFile );

end;


procedure Output;
begin

   assign( outFile, 'nishtel.out');
   rewrite( outFile );
   writeln( outFile, sol);
   close( OutFile );

end;


(* simulacija liste preko counting sorta *)
procedure ListSimulation;
var
   i: longint;

begin

   p[0] := 0;
   for i := 1 to n do
      p[ i ] := p[ i - 1 ] + deg[ i - 1 ];

   for i := 1 to m do begin
      adj[ p[ a1[ i ] ] ] := b1[ i ];
      weight[ p[ a1[ i ] ] ] := w1[ i ];
      p[ a1[ i ] ] := p[ a1[ i ] ] + 1;
   end;

   for i := 1 to n do
      p[ i ] := p[ i - 1 ] + deg[ i - 1 ];

end;


procedure updateHeap( u, newVal : longint );
var
   f, s : longint;

begin

   d[ u ] := newVal;
   s := posInHeap[ u ];
   f := s div 2;

   while ((f <> 0) and (d[ h[ f ] ] > d[ u ])) do begin
      h[ s ] := h[ f ];
      posInHeap[ h[ f ] ] := s;
      s := f; f := s div 2;
   end;

   h[ s ] := u;
   posInHeap[ u ] := s;

end;


function extractMin: longint;
var
   f, s, u, min : longint;

begin

   min := h[ 1 ];
   u := h[ heap_size ];
   h[ 1 ] := u;
   heap_size := heap_size - 1;
   f := 1;
   s := 2 * f;
   if ((heap_size > s) and (d[ h[ s + 1 ] ] < d[ h[ s ] ])) then
      s := s + 1;

   while ((s <= heap_size) and (d[ u ] > d[ h[ s ] ])) do begin
      h[ f ] := h[ s ];
      posInHeap[ h[ s ] ] := f;
      f := s; s := 2 * f;
      if ((heap_size > s) and (d[ h[ s + 1 ] ] < d[ h[ s ] ])) then
         s := s + 1;
   end;

   h[ f ] := u;
   posInHeap[ u ] := f;
   extractMin := min;

end;


procedure Dijkstra( START : longint );
var
  u, v, w : longint;

begin

   for i := 1 to n do begin
      d[ i ] := inf;
      h[ i ] := i;
      posInHeap[ i ] := i;
   end;
   heap_size := n;
   updateHeap( START, 0 );

   while (heap_size > 0) do begin
      u := extractMin;
      for i := p[ u ] to p[ u ] + deg[ u ] - 1 do begin
         v := adj[ i ]; w := weight[ i ];
         if (d[ u ] + w < d[ v ]) then
            updateHeap( v, d[ u ] + w );
      end;
   end;

end;


begin

   Input;
   ListSimulation;

   Dijkstra( A );
   for i := 1 to n do dA[ i ] := d[ i ];
   Dijkstra( B );
   for i := 1 to n do dB[ i ] := d[ i ];

   sol := m - 2 * n + 2;
   for i := 1 to n do mark[ i ] := false;

   for u := 1 to n do
      for i := p[ u ] to p[ u ] + deg[ u ] - 1 do begin
         v := adj[ i ]; w := weight[ i ];
         if ((not mark[ v ]) and (dA[ v ] - dA[ u ] = w) and (dB[ v ] - dB[ u ] = w))
         then begin
            mark[ v ] := true;
            sol := sol + 1;
         end;
      end;

   Output;

end.