ΚΕΠΛΗΝΕΤ Ηλείας

Πανελλήνιο Σχολικό Δίκτυο

Το Στέκι των Πληροφορικών

SaferInternet.gr

SafeLine.gr

 

Εφαρμογή Χαρτογράφησης Μονάδων Εκπαίδευσης Ν. Ηλείας

Ενημερωτικό Δελτίο «ΤΠΕ στην Εκπαίδευση» - ΚΕ.ΠΛΗ.ΝΕ.Τ. Ηλείας

25ος Πανελλήνιος Διαγωνισμός Πληροφορικής

2ος Πανελλήνιος Διαγωνισμός Εκπαιδευτικής Ρομποτικής WRO (World Robot Olympiad)

Ημέρα Ασφαλούς Διαδικτύου 2013

Ανακύκλωση Ηλεκτρικών και Ηλεκτρονικών Συσκευών

 

Ιστοσελίδες μονάδων

Αναφορά προβλημάτων

Διαδικτυακά εργαλεία τεχνικού ελέγχου

20ος Πανελλήνιος Διαγωνισμός Πληροφορικής
(Σχολικό Έτος 2007-8)

Θέμα Α' Φάσης: Φρυκτωρίες

imageΟι αρχαίοι Έλληνες δεν άφησαν πίσω τους μόνο μια ασύλληπτη πνευματική κληρονομιά με τα θεωρητικά έργα τους: Αλλά, και με τα τεχνολογικά τους επιτεύγματα, παρέδωσαν στην ανθρωπότητα έναν τεχνολογικό πολιτισμό, που αν είχε αξιοποιηθεί, οι σημερινές μας δυνατότητες θα ήταν ασύγκριτα μεγαλύτερες. Τα κατασκευαστικά τους θαύματα, όπως ο χιλιομετρητής των Αθηνών, η ατμομηχανή του Ήρωνος, ο αστρολάβος των Αντικυθήρων, οι μηχανές του Αρχιμήδους κα. αποτελούν μερικά από τα πολλά και πολύτιμα δημιουργήματά τους. Εξ’ ίσου σημαντικά ήταν και τα επιτεύγματά τους στις επικοινωνίες. Χρησιμοποιώντας οπτικές ψηφιακές επικοινωνίες από το 12 πΧ. αιώνα μετέφεραν το μήνυμα της νίκης από την Τροία στις Μυκήνες μέσα σε λίγα 24ωρα. Από τα μέσα του 9ου πΧ χρησιμοποίησαν κωδικοποίηση του Ελληνικού αλφαβήτου (Καδμεία γραφή) για τη μετάδοση κειμένων με οπτική κωδικοποίηση σε Καρτεσιανές συντεταγμένες! Το εκπληκτικό είναι ότι κωδικοποίησαν το αλφάβητο με βάση την εντροπία του κάθε γράμματος. Στον παρακάτω πίνακα φαίνεται για παράδειγμα μια τέτοια κωδικοποίηση, όπου το γράμμα Μ αντιστοιχεί σε τρεις οριζόντια και τρεις κάθετα αναμμένους δαυλούς.

  ¥ ¥ ¥    
¥ Ε Ο Θ Ζ  
¥ Α Β Δ Γ Σ
¥ Ι Ν Μ Κ Λ
  Η Τ Ρ Φ Ω
  Υ Π Ξ Χ Ψ

Η βασική αρχή αυτής της κωδικοποίησης είναι τα γράμματα να ταξινομούνται με βάση τη φθίνουσα σειρά εμφάνισής τους. Τα γράμματα με τη μεγαλύτερη συχνότητα εμφάνισης θα απαιτούν το άναμμα λιγότερων δαυλών και αντίστοιχα αυτά με τη μικρότερη συχνότητα εμφάνισης, περισσότερων.

Πρόβλημα: Να αναπτύξετε ένα πρόγραμμα σε μια από τις γλώσσες του ΙΟΙ το οποίο: Θα λαμβάνει κείμενα στην Ελληνική και αφού μετρήσει πόσες φορές εμφανίζεται κάθε χαρακτήρας (Κεφαλαία Ελληνικά & κενό) θα τους εμφανίζει με σειρά φθίνουσας εμφάνισης, εμφανίζοντας και την αντίστοιχη συχνότητα εμφάνισης ώστε να τύχουν καλλίτερης κωδικοποίησης.

Αρχεία Εισόδου: Τα αρχεία εισόδου με όνομα friktories.in είναι αρχεία κειμένου με την εξής δομή: Έχουν τουλάχιστον μία γραμμή με ένα Ελληνικό κείμενο (64 – 1000000 χαρακτήρες). Κάθε χαρακτήρας αντιστοιχεί ακριβώς σε ένα byte.

Αρχεία Εξόδου: Τα αρχεία εξόδου με όνομα friktories.out είναι αρχεία κειμένου με την εξής δομή: Έχουν 25 ακριβώς γραμμές και σε κάθε μία υπάρχει ένας χαρακτήρας από τον συχνότερα εμφανιζόμενο (1η) μέχρι τον λιγότερο συχνά εμφανιζόμενο (25η). Μετά από κάθε χαρακτήρα παρεμβάλλεται ο χαρακτήρας διάστημα (space) και αμέσως μετά η συχνότητα εμφάνισης του. (Πόσες φορές δηλαδή εμφανίστηκε στο κείμενο). Αν δύο χαρακτήρες έχουν την ίδια συχνότητα εμφάνισης τότε ταξινομούνται με την αλφαβητική τους σειρά. (Ο χαρακτήρας διάστημα θεωρείται 25ος).

Παραδείγματα Αρχείων Εισόδου - Εξόδου:
1ο Παράδειγμα:
friktories.in friktories.out

ΜΗΝΙΝ ΑΕΙΔΕ ΘΕΑ ΠΗΛΗΙΑΔΕΩ ΑΧΙΛΗΟΣ ΟΥΛΟΜΕΝΗΝ, Η ΜΥΡΙ ΑΧΑΙΟΙΣ ΑΛΓΕ ΕΘΗΚΕ, ΠΟΛΛΑΣ Δ ΙΦΘΙΜΟΥΣ ΨΥΧΑΣ ΑΙΔΙ ΠΡΟΙΑΨΕΝ ΗΡΩΩΝ,

  17
Ι 12
Α 11
Ε 9
Η 8
Ο 7
Λ 6
Ν 6
Σ 5
Δ 4
Μ 4
Υ 4
Θ 3
Π 3
Ρ 3
Χ 3
Ω 3
Ψ 2
Γ 1
Κ 1
Φ 1
Β 0
Ζ 0
Ξ 0
Τ 0

Ομήρου Ιλιάδα, Ραψωδία Α΄, στίχοι 1-4

Μετάφραση: Μούσα, τραγουδά το θυμό του ξακουστού Αχιλλέα, τον έρμο! π' όλους πότισε τους Αχαιούς φαρμάκια, και πλήθος έστειλε ψυχές λεβέντικες στον Άδη

Μετάφραση Αλεξάνδρου Πάλη (Από http://el.wikisource.org/wiki/)

2ο Παράδειγμα:
friktories.in friktories.out

ΞΡΩΜΕΘΑ ΓΑΡ ΠΟΛΙΤΕΙΑ ΟΥ ΖΗΛΟΥΣΥ ΤΟΥΣ ΤΩΝ ΠΕΛΑΣ ΝΟΜΟΥΣ ΠΑΡΑΔΕΙΓΜΑ ΔΕ ΜΑΛΛΟΝ ΑΥΤΟΙ ΟΝΤΕΣ ΤΙΣΙΝ Η ΜΙΜΟΥΜΕΝΟΙ ΕΤΕΡΟΥΣ. ΚΑΙ ΟΝΟΜΑ ΜΕΝ ΔΙΑ ΤΟ ΜΗ ΕΣ ΟΛΙΓΟΥΣ ΑΛΛ’ ΕΣ ΠΛΕΙΟΝΑΣ ΟΙΚΕΙΝ ΔΗΜΟΚΡΑΤΙΑ ΚΕΚΛΗΤΑΙ ΜΕΤΕΣΤΙ ΔΕ ΚΑΤΑ ΜΕΝ ΤΟΥΣ ΝΟΜΟΥΣ ΠΡΟΣ ΤΑ ΙΔΙΑ ΔΙΑΦΟΡΑ ΠΑΣΙ ΤΟ ΙΣΟΝ, ΚΑΤΑ ΔΕ ΤΗΝ ΑΞΙΩΣΙΝ, ΩΣ ΕΚΑΣΤΟΣ ΕΝ ΤΩ ΕΥΔΟΚΙΜΕΙ, ΟΥΚ ΑΠΟ ΜΕΡΟΥΣ ΤΟ ΠΛΕΟΝ ΕΣ ΤΑ ΚΟΙΝΑ Η ΑΠ’ ΑΡΕΤΗΣ ΠΡΟΤΙΜΑΤΑΙ, ΟΥΔ ΑΥ ΚΑΤΑ ΠΕΝΙΑΝ, ΕΧΩΝ ΓΕ ΤΙ ΑΓΑΘΟΝ ΔΡΟΣΑΙ ΤΗΝ ΠΟΛΙΝ, ΑΞΙΩΜΑΤΟΣ ΑΦΑΝΕΙΑ ΚΕΚΩΛΥΤΑΙ ΕΛΕΥΘΕΡΩΣ ΔΕ ΤΑ ΤΕ ΠΡΟΣ ΤΟ ΚΟΙΝΟΝ ΠΟΛΙΤΕΥΟΜΕΝ ΚΑΙ ΕΣ ΤΗΝ ΠΡΟΣ ΑΛΛΗΛΟΥΣ ΤΩΝ ΚΑΘ’ ΗΜΕΡΑΝ ΕΠΙΤΗΔΕΥΜΑΤΩΝ ΥΠΟΨΙΑΝ, ΟΥ ΔΙ ΟΡΓΗΣ ΤΟΝ ΠΕΛΑΣ, ΕΙ ΚΑΘ’ ΗΔΟΝΗΝ ΤΙ ΔΡΑ, ΕΧΟΝΤΕΣ, ΟΥΔΕ ΑΖΗΜΙΟΥΣ ΜΕΝ, ΛΥΠΗΡΑΣ ΔΕ ΤΗ ΟΨΕΙ ΑΧΘΗΔΟΝΑΣ ΠΡΟΣΤΙΘΕΜΕΝΟΙ. ΑΝΕΠΑΧΘΩΣ ΔΕ ΤΑ ΙΔΙΑ ΠΡΟΣΟΜΙΛΟΥΝΤΕΣ ΤΑ ΔΗΜΟΣΙΑ ΔΙΑ ΔΕΟΣ ΜΑΛΙΣΤΑ ΟΥ ΠΑΡΑΝΟΜΟΥΜΕΝ, ΤΩΝ ΤΕ ΑΙΕΙ ΕΝ ΑΡΧΗ ΟΝΤΩΝ ΑΚΡΟΑΣΕΙ ΚΑΙ ΤΩΝ ΝΟΜΩΝ, ΚΑΙ ΜΑΛΙΣΤΑ ΑΥΤΩΝ ΟΣΟΙ ΤΕ ΕΠ’ ΩΦΕΛΙΑ ΤΩΝ ΑΔΙΚΟΥΜΕΝΩΝ ΚΕΙΝΤΑΙ ΚΑΙ ΟΣΟΙ ΑΓΡΑΦΟΙ ΟΝΤΕΣ ΑΙΣΧΥΝΗΝ ΟΜΟΛΟΓΟΥΜΕΝΗΝ ΦΕΡΟΥΣΙΝ.

  156
Α 89
Ο 84
Ε 71
Ι 70
Ν 62
T 57
Σ 51
Μ 34
Υ 34
Δ 25
Λ 25
Ρ 25
Η 24
Κ 24
Π 24
Ω 20
Γ 8
Θ 8
Χ 6
Φ 5
Ξ 3
Ζ 2
Ψ 2
Β 0

Θουκυδίδη Περικλέους Επιτάφιος Λόγος, (Ιστοριών Β΄ §37)

Μετάφραση: Έχουμε δηλαδή πολίτευμα, το οποίο δεν αντιγράφει τους νόμους άλλων, μάλλον δε εμείς οι ίδιοι είμαστε υπόδειγμα σε μερικούς παρά μιμούμαστε άλλους. Και ονομάζεται μεν δημοκρατία, γιατί η διοίκηση είναι στα χέρια των πολλών και όχι των ολίγων. Όλοι έχουν τα ίδια δικαιώματα έναντι δε των νόμων στις ιδιωτικές τους διαφορές, ενώ ως προς την θέση τους στον δημόσιο βίο κάθε ένας, ανάλογα με την επίδοση σε κάποιο τομέα, προτιμάται για ένα από τα δημόσια αξιώματα, και όχι από την πολιτική του παράταξη όσο από την αρετή του, ούτε εξαιτίας της φτώχειας, ενώ έχει την ικανότητα να παράσχει κάποια υπηρεσία στην πατρίδα του, εμποδίζεται από το γεγονός ότι είναι άγνωστος. Ζούμε ελεύθερα, και ως πολίτες στον δημόσιο βίο και ως άτομα στον ιδιωτικό, στις επιδιώξεις μας της καθημερινής ζωής, κατά τις οποίες δεν κοιτάμε ο ένας στον άλλον με καχυποψία, δεν θυμώνουμε με τον γείτονά μας, όταν κάνει σύμφωνα με την ευχαρίστησή του, ούτε παίρνουμε μια φυσιογνωμία σκυθρωπή, η οποία μπορεί να μην βλάπτει τον άλλο, πάντως όμως είναι δυσάρεστη. Ενώ δε στην ιδιωτική μας ζωή συναναστρεφόμαστε χωρίς να ενοχλεί ο ένας τον άλλον, στην δημόσιά μας ζωή από σεβασμό προ πάντων δεν παραβαίνουμε τους νόμους, υπακούμε σε όσους κάθε φορά έχουν τα αξιώματα και στους νόμους, και περισσότερο σε εκείνους από τους νόμους, που έχουν θεσπιστεί για ωφέλεια των αδικούμενων, και σε άλλους, οι οποίοι αν και άγραφοι, η παράβασή τους φέρνει πανθομολογούμενη ντροπή.

Μετάφραση Βασιλείου Συμεωνίδη (Από http://users.sch.gr/symfo/sholio/arhea/epitafios_mtfr.htm)


Ενδεικτική λύση σε PASCAL
(* Μιχάλης Γαλιανάκης (2ο ΤΕΕ Ρεθύμνου) *)

program friktories(input,output) ;
const
  stath=25 ;
  
type
  typos=0..1000000 ;
  egrafi=record
    a:byte ;
    syn:typos ;
  end ;

var
  ar1:text ;
  pin:array[1..stath]of egrafi ;
  backup:egrafi ;
  a,w,i:byte ;
  fr:string ;
 
begin
  for i:=1 to stath do
    begin
      pin[i].a:=i+127 ;
      pin[i].syn:=0 ;
    end ;
  assign(ar1,'friktories.in') ;
  reset(ar1) ;
  while not eof(ar1) do
    begin
      repeat
        read(ar1,fr) ;
        w:=length(fr) ;
        for i:=1 to w do
          begin
            a:=ord(fr[i]) ;
            if (a<128)or(a>151) then
              begin
                if a=32 then
                  a:=152
                else
                  a:=0 ;
              end ;
            if a<>0 then
              pin[a-127].syn:=pin[a-127].syn+1 ;
          end ;
      until w<>255 ;
      readln(ar1) ;
    end ;
  close(ar1) ;
  w:=1 ;
  repeat
    w:=w+1 ;
    a:=1 ;
    for i:=stath downto w do
      if pin[i-1].syn<pin[i].syn then
        begin
          a:=0 ;
          backup:=pin[i] ;
          pin[i]:=pin[i-1] ;
          pin[i-1]:=backup ;
        end ;
  until (a=1)or(w=stath) ;
  assign(ar1,'friktories.out') ;
  rewrite(ar1) ;
  for i:=1 to stath do
    begin
      if pin[i].a=152 then
      pin[i].a:=32 ;
      writeln(ar1,chr(pin[i].a),' ',pin[i].syn);
    end ;
  close(ar1) ;
  halt(0) ;
end.

Ενδεικτική λύση σε C
/* Ιωάννης Χατζημίχος (8ο ΓΕΛ Λαρίσης) */
      
#include <stdio.h>
#include <stdlib.h>
#define MSIZE 1000000

int cnt[26];
char a[MSIZE+1];

int main(void) {
  freopen("friktories.in", "r", stdin);
  freopen("friktories.out", "w", stdout);
  unsigned char c;
  int i, j, vis=0, m;
  cnt[25] = -1;
  
  while(gets(a)) {
    for (i=0; a[i]!='\0'; i++) {
      c = a[i];
      if ( c >= 128 && c <= 151 ) cnt[c-128]++;
      else if ( c == 32 ) cnt[24]++;
    }
  }
  
  for (i=0; i<25; i++) {
    m = 25;
    for (j=0; j<25; j++) {
     if ( ( vis|(1<<j) ) != vis && cnt[j] > cnt[m] ) m = j;
    }
    vis |= (1<<m);
    printf("%c %d\n", (m==24?' ':m+128), cnt[m]);
  }
  
  return 0;
}

Ενδεικτική λύση σε C++
/* Άγγελος Καθαρόπουλος (Αρσάκειο ΓΕΛ Θεσσαλονίκης) */
     
#include <stdio.h>

struct freq
{
  int f;
  unsigned char ch;
};

void mySort(freq *table,int size);


int main ()
{
  FILE * frikin;
  FILE * frikout;
  frikin = fopen("friktories.in","rb");
  frikout = fopen("friktories.out","w");
  if (frikin == NULL || frikout == NULL) 
  { 
    perror("Couldn't open a file"); 
    return -1; 
  }
 
  freq myChars[25];
  for (int i = 0; i < 25; i++) { myChars[i].f = 0;
    myChars[i].ch=i+128; }
 
  myChars[24].ch = 32;
  long size,res;
  unsigned char *container;
  fseek(frikin,0,SEEK_END);
  size = ftell(frikin);
  rewind(frikin);
  container = new unsigned char[size];
  if (container == NULL) {fclose(frikout); fclose(frikin);
    perror("Error allocating the memory needed to read the file"); return -1; }

  res = fread(container,1,size,frikin);
  if (res != size) 
  {
    fclose(frikout); fclose(frikin); 
    delete [] container; 
    perror("Error reading file into memory");
    return -1; 
  }

  fclose(frikin);
  for (unsigned char *temp = container; *temp; temp++)
  {
    if (*temp < 152 && *temp > 127)
    {
      myChars[(*temp)-128].f++;
    }
    else if (*temp == 32)
    {
      myChars[24].f++;
    }
  }
  mySort(myChars,25);
  for (int i = 0; i < 25; i++) 
  { 
    fprintf(frikout,"%c %d\n",myChars[i].ch,myChars[i].f); 
  }
  delete [] container;
  fclose(frikout);
  return 0;
}


void mySort(freq *table, int size)
{
  unsigned short swap = 1;
  freq temp;
  while (swap)
  {
    swap = 0;
    for (int i = 0; i < size-1; i++)
    {
      if (table[i].f < table[i+1].f)
      {
        temp = table[i];
        table[i] = table[i+1];
        table[i+1] = temp;
        swap = 1;
      }
    }
  }
}

Θέμα Β' Φάσης: Σαμποτάζ στο Γοργοπόταμο

imageΤη νύχτα της 25ης προς 26η Νοεμβρίου του 1942 οι ενωμένες αντιστασιακές δυνάμεις του ΕΛΑΣ υπό τον Άρη Βελουχιώτη και του ΕΔΕΣ υπό τον Ναπολέοντα Ζέρβα πραγματοποίησαν το μεγαλύτερο ίσως σαμποτάζ στην κατεχόμενη Ευρώπη: Διέκοψαν τη γραμμή εφοδιασμού της Βέρμαχτ, ανατινάζοντας τη γέφυρα του Γοργοποτάμου στη Φθιώτιδα. 60 αντάρτες του ΕΛΑΣ ανέλαβαν το νότιο άκρο, 40 αντάρτες του ΕΔΕΣ το βόρειο, 12 Άγγλοι σαμπτοτέρ υπονόμευσαν τη γέφυρα και ο καπετάν Νικηφόρος του ΕΛΑΣ με 30 άνδρες έμειναν κρυμμένοι - εφεδρεία προκειμένου να επέμβουν εφόσον χρειάζονταν. Ο καπετάν Νικηφόρος εξέφρασε τη δυσαρέσκειά του που έμεινε σε εφεδρεία, αλλά υπήρξε ο καθοριστικός παράγων της επιτυχίας. Μόλις δόθηκε το σήμα ο καπετάν Νικηφόρος κινήθηκε ανάμεσα από ναρκοπέδια και τα πεδία βολής των πολυβολείων, αναγνωρισμένα από πριν, για να φθάσει στο βόρειο άκρο που υπήρξε πρόβλημα. Ο καπετάν Νικηφόρος και οι αντάρτες του έπρεπε να κινηθούν, επιλέγοντας τη συντομότερη διαδρομή, μόνο εμπρός ή δεξιά ή αριστερά, με μικρά βήματα και χωρίς να βγουν έξω από το πεδίο της μάχης, προκειμένου να κατορθώσουν να φθάσουν έγκαιρα στο επιθυμητό σημείο. Ήταν σαν κινούνταν σε μία τεράστια σκακέρια γεμάτη νάρκες!

  1 2 3 4 5
  (σημείο εκκίνησης)      
  #        
1 S1 S2 S3 * *
2 * * S4 *  
3 *   S5 * *
4     S6 S7  
5     S7 S8 *
6 *   * S9 *
7 * * * S10  
        #  
        (σημείο προορισμού)

Πρόβλημα: Να αναπτύξετε ένα πρόγραμμα σε μια από τις γλώσσες του ΙΟΙ το οποίο: Α) Θα διαβάζει από ένα αρχείο τις διαστάσεις του ορθογώνιου πεδίου μάχης, τον αριθμό και τη θέση (συντεταγμένες) των ναρκών, το σημείο εκκίνησης και το σημείο προορισμού. Β) Θα υπολογίζει τη συντομότερη διαδρομή από το σημείο εκκίνησης έως το σημείο προορισμού, η οποία σε καμία περίπτωση δεν πρέπει να ξεπερνά τις διαστάσεις του ορθογωνίου ή να περνά πάνω από νάρκη. Η διαδρομή πρέπει να περιλαμβάνει μόνο επιτρεπτές κινήσεις (κάτω, δεξιά, αριστερά). Γ) Θα δίνει σαν έξοδο ένα αρχείο που θα έχει τον αριθμό των κινήσεων και τις συντεταγμένες τους. Αν δεν υπάρχει τέτοια διαδρομή θα τυπώνει τον αριθμό 0.

Μια κίνηση προς τα κάτω ισοδυναμεί με αύξηση του Υ, μια κίνηση προς τα δεξιά με αύξηση του Χ ενώ μια κίνηση προς τα αριστερά με μείωση του Χ.

Αρχεία Εισόδου:

Τα αρχεία εισόδου με όνομα sabotage.in είναι αρχεία κειμένου με την εξής δομή: Στην πρώτη γραμμή έχουν δύο αριθμούς (χωριζόμενους από ένα κενό) X, Y (1 < X, Y <= 1000) τις διαστάσεις του πεδίου της μάχης. Στη δεύτερη γραμμή υπάρχει ένας αριθμός Ν (1 <= Ν <= 1000000), που δίνει το αριθμό των ναρκών ή των σημείων ορατότητας των πολυβολείων. Οι επόμενες Ν γραμμές έχουν τις συντεταγμένες των παραπάνω, με τη μορφή Χi , Υi (χωριζόμενες με ένα κενό). Η προτελευταία γραμμή έχει τις συντεταγμένες του σημείου εκκίνησης και η τελευταία τις συντεταγμένες του σημείου προορισμού (χωριζόμενες με ένα κενό).

Αρχεία Εξόδου:

Τα αρχεία εξόδου με όνομα sabotage.out είναι αρχεία κειμένου με την εξής δομή: Στη πρώτη γραμμή υπάρχει ο αριθμός των κινήσεων Μ (0 < Μ < 1000000). Οι επόμενες Μ γραμμές έχουν τις συντεταγμένες των κινήσεων, με τη μορφή Χi, Υi (χωριζόμενες με ένα κενό). Εάν δεν υπάρχει δυνατή διαδρομή μόνο το 0.

Παρατηρήσεις:
Παραδείγματα Αρχείων Εισόδου - Εξόδου:
1ο Παράδειγμα (δύο ισοδύναμα αρχεία εξόδου)
sabotage.in sabotage.out sabotage.out

5 7
15
4 1
5 1
1 2
2 2
4 2
1 3
4 3
5 3
5 5
1 6
3 6
5 6
1 7
2 7
3 7
1 1
4 7

10
1 1
2 1
3 1
3 2
3 3
3 4
4 4
4 5
4 6
4 7

10
1 1
2 1
3 1
3 2
3 3
3 4
3 5
4 5
4 6
4 7

2ο Παράδειγμα
sabotage.in sabotage.out

5 7
5
1 2
2 2
3 2
4 2
5 2
4 1
2 7

0

Περιορισμοί:

Χρόνος εκτέλεσης: 10 δευτερόλεπτα.
Μέγιστη απαίτηση μνήμης: 32 MB.


Ενδεικτική λύση σε PASCAL
(* ΔΗΜΗΤΡΗΣ ΜΟΥΔΗΛΟΣ ΓΕΛ ΑΝΑΒΥΣΣΟΥ *)
     
Program sabotage;
var
  width,height,mines,mine_x,mine_y,i:longint;
  start_x,start_y,end_x,end_y: longint;
  map:array [1..1000,1..1000] of longint;
  c_x:array[1..10000] of longint ;
  c_y:array[1..10000] of longint ;
  t_x:array[1..10000] of longint;
  t_y:array[1..10000] of longint ;
  N,temp_step,step:longint;
  x,y,tx,ty:longint;
  ok:boolean;
  fdata,fdata2:text;

Begin
  assign (fdata,'sabotage.in');
  reset (fdata);
  read (fdata,width);
  read (fdata,height);
  read (fdata,mines);
  if mines<>0 then
    begin
      for i:=1 to mines do
        begin
          read (fdata,mine_x);
          read (fdata,mine_y);
          map[mine_x,mine_y]:=-1;
        end;
    end;
    
  read (fdata,start_x);
  read (fdata,start_y);
  read (fdata,end_x);
  read (fdata,end_y);
  
  c_x[1]:=end_x;
  c_y[1]:=end_y;
  t_x[1]:=end_x;
  t_y[1]:=end_y;
  N:=1;
  temp_step:=0;
  step:=1;
  ok:=true;
  
  While (map[start_x,start_y]=0) and (ok=true) do
    begin
      ok:=false;
      For i:=1 to step do
        begin
          if c_x[i]+1<=width then
            begin
              if (map[c_x[i]+1,c_y[i]]=0) then
                begin
                  map[c_x[i]+1,c_y[i]]:=N;
                  temp_step:=temp_step+1;
                  t_x[temp_step]:=c_x[i]+1;
                  t_y[temp_step]:=c_y[i];
                  ok:=true;
                end;
            end;
          if c_x[i]-1>0 then
            begin
              if (map[c_x[i]-1,c_y[i]]=0) then
                begin
                  map[c_x[i]-1,c_y[i]]:=N;
                  temp_step:=temp_step+1;
                  t_x[temp_step]:=c_x[i]-1;
                  t_y[temp_step]:=c_y[i];
                  ok:=true;
                end;
            end;
          if c_y[i]-1>0 then
            begin
              if (map[c_x[i],c_y[i]-1]=0) then
                begin
                  map[c_x[i],c_y[i]-1]:=N;
                  temp_step:=temp_step+1;
                  t_x[temp_step]:=c_x[i];
                  t_y[temp_step]:=c_y[i]-1;
                  ok:=true;
                end;
            end;
        end;
      For i:=1 to temp_step do
        begin
          c_x[i]:=t_x[i];
          c_y[i]:=t_y[i];
        end;
      step:=temp_step;
      N:=N+1;
      temp_step:=0;
    end;
    
  close(fdata);
  map[end_x,end_y]:=0;
  assign (fdata2,'sabotage.out');
  rewrite (fdata2);
  
  if map[start_x,start_y]<>0 then
    begin
      x:=start_x;
      y:=start_y;
      writeln(fdata2,map[start_x,start_y]+1);
      writeln(fdata2,x,' ',y);
      For i:=map[start_x,start_y] downto 1 do
        begin
          tx:=x;
          ty:=y;
          ok:=false;
          if y+1<=height then
            begin
              if (ok=false) and (map[x,y+1]=i-1) then
                begin
                  ty:=y+1;
                  writeln(fdata2,x,' ',ty);
                  ok:=true;
                end;
            end;
          if x-1>0 then
            begin
              if (ok=false) and (map[x-1,y]=i-1) then
                begin
                  tx:=x-1;
                  writeln(fdata2,tx,' ',y);
                  ok:=true;
                end;
            end;
          if x+1<=width then
            begin
              if (ok=false) and (map[x+1,y]=i-1) then
                begin
                  tx:=x+1;
                  writeln(fdata2,tx,' ',y);
                  ok:=true;
                end;
            end;
          x:=tx;
          y:=ty;
        end;
    end
  else
    begin
      writeln(fdata2,'0');
    end;
  close(fdata2);
  halt(0);
End.

Ενδεικτική λύση σε C
/* ΑΝΑΣΤΑΣΙΟΣ ΓΕΡΜΑΝΙΔΗΣ ΚΟΛΛΕΓΙΟ ΨΥΧΙΚΟΥ*/
      
#include <stdio.h>
#define MAXSIZE 1001

int Qx[MAXSIZE*MAXSIZE], Qy[MAXSIZE*MAXSIZE];
char field[MAXSIZE][MAXSIZE];

int main(void) {
  FILE *in, *out;
  
  in=fopen("sabotage.in", "r");
  out=fopen("sabotage.out", "w");
  
  int x=0, y=0, startx=0, starty=0, endx=0, endy=0,
  mines=0, minex=0, miney=0, steps=0,
  tailqx=0, tailqy=0, headqx=0, headqy=0,
  i=0, p=0, direction=0, mode=0,
  ux=0, uy=0, vx=0, vy=0, kx=0, ky=0,
  found=0, finished=0;
  
  for (i=1; i<x+1; i++) {
    for (p=1; p<y+1; p++) {
      field[i][p] = 0;
    }
  }
  
  for (i=0;i<(x+1)*(y+1);i++) {
    Qx[i]=0;
    Qy[i]=0;
  }
  
  fscanf(in,"%d %d\n", &x, &y);
  if (startx>endx) { direction=1; }
  fscanf(in,"%d\n", &mines);
  
  for (i=0;i<mines;i++) {
    fscanf(in,"%d %d\n", &minex, &miney);
    field[minex][miney]=1;
    minex=0;
    miney=0;
  }
  
  fscanf(in,"%d %d\n", &startx, &starty);
  fscanf(in,"%d %d\n", &endx, &endy);
  fclose(in);
  
  field[startx][starty]=4;
  Qx[tailqx++]=startx;
  Qy[tailqy++]=starty;
  
  while (!finished) {
    ux=Qx[headqx];
    uy=Qy[headqy];
    if (ux==0 && uy==0) {
      finished=1;
    }
    
    for (i=0;i<3 && ux!=0 && uy!=0;i++) {
      vx=0;
      vy=0;
      if (!direction) {
        if (field[ux+1][uy]==0 && ux!=x) {
          vx=ux+1;
          vy=uy;
          mode=1;
        }
        else if (field[ux][uy+1]==0 && uy!=endy) {
          vy=uy+1;
          vx=ux;
          mode=2;
        }
        else if (field[ux-1][uy]==0 && ux!=1) {
          vx=ux-1;
          vy=uy;
          mode=3;
        }
      }
      else if (direction) {
        if (field[ux-1][uy]==0 && ux!=1) {
          vx=ux-1;
          vy=uy;
          mode=3;
        }
        else if (field[ux][uy+1]==0 && uy!=endy) {
          vy=uy+1;
          vx=ux;
          mode=2;
        }
        else if (field[ux+1][uy]==0 && ux!=x) {
          vx=ux+1;
          vy=uy;
          mode=1;
        }
      }  
      
      if (vx != 0 && vy != 0 && field[vx][vy]==0) {
        field[vx][vy]=mode;
        if (vx==endx && vy==endy) {
          found=1;
          finished=1;
        }
        Qx[tailqx++]=vx;
        Qy[tailqy++]=vy;
      }
    }
    headqx++;
    headqy++;
    steps++;
  }
  
  if (!found) {
    fprintf(out,"%d\n",0);
  }
  else {
    kx=endx;
    ky=endy;
    for(i=0;i<(x+1)*(y+1);i++) {
      Qx[i]=0;
      Qy[i]=0;
    }
    
    for (i=steps+1; i>0; i--) {
      if (field[kx][ky]!=4) {
        if (field[kx][ky]==1) {
          Qx[i]=kx-1;
          Qy[i]=ky;
        }
        else if (field[kx][ky]==2) {
          Qx[i]=kx;
          Qy[i]=ky-1;
        }
        else if (field[kx][ky]==3) {
          Qx[i]=kx+1;
          Qy[i]=ky;
        }
        kx=Qx[i];
        ky=Qy[i];
      }
    }
    
    for (p=0; Qx[p]==0;p++) { ; }
    
    fprintf(out,"%d\n", steps-p+3);
    for (i=p;i<steps+2;i++) {
      fprintf(out,"%d %d\n", Qx[i], Qy[i]);
    }
    
    fprintf(out,"%d %d\n", endx, endy);
  }
  fclose(out);
  return(0);
}

Ενδεικτική λύση σε C++
/* ΙΩΑΝΝΗΣ ΧΑΤΖΗΜΙΧΟΣ 8ο ΓΕΛ ΛΑΡΙΣΑΣ */

#include <cstdio>
#include <cstdlib>
#include <queue>

using namespace std;

int moves[3][2] = { {0, -1}, {0, 1}, {1, 0} };

struct point {
  int r;
  int c;
};

int par[1001][1001], R, C;


void BFS(int r, int c) {
  queue<point> Q;
  point cur, next;
  int i;
  cur.r = r;
  cur.c = c;
  Q.push(cur);
  
  while(!Q.empty()) {
    cur = Q.front();
    Q.pop();
    for (i=0; i<3; i++) {
      next.r = cur.r + moves[i][0];
      next.c = cur.c + moves[i][1];
      if ( next.r <= 0 || next.r > R || next.c <= 0 || next.c > C ) continue;
      if ( par[next.r][next.c] ) continue;
      par[next.r][next.c] = i+1;
      Q.push(next);
    }
  }
}


int main(void) {
  FILE *in = fopen("sabotage.in", "r"), *out =
    fopen("sabotage.out", "w");
  int i, M, r, c, sr, sc;
  int mv[1000001], mvcnt = 0, mvid;
  
  fscanf(in, "%d %d %d", &C, &R, &M);
  for (i=1; i<=M; i++) {
    fscanf(in, "%d %d", &c, &r);
    par[r][c] = 8888;
  }
  
  fscanf(in, "%d %d", &sc, &sr);
  BFS(sr, sc);
  fscanf(in, "%d %d", &c, &r);
  
  if ( !par[r][c] ) {
    fprintf(out, "0\n");
  }
  else {
    while (r!=sr || c!=sc) {
      mvid = par[r][c]-1;
      mv[++mvcnt] = mvid;
      r -= moves[mvid][0];
      c -= moves[mvid][1];
    }
    fprintf(out, "%d\n%d %d\n", mvcnt+1, sc, sr);
    r = sr; c = sc;
    for (i=mvcnt; i>=1; i--) {
      r += moves[mv[i]][0];
      c += moves[mv[i]][1];
      fprintf(out, "%d %d\n", c, r);
    }
  }
  
  fclose(in); fclose(out); return 0;
}

1ο Θέμα Τελικής Φάσης: Data Blocks

Η Ελληνική Εταιρεία Επιστημόνων & Επαγγελματιών Πληροφορικής & Επικοινωνιών (ΕΠΥ), με τη συμπλήρωση 30 χρόνων προσφοράς, εγκατέστησε έναν web server για τη δημοσιοποίηση του τεράστιου υλικού που έχει παραχθεί. Το υλικό αυτό είναι αποθηκευμένο σε μονάδες αποθήκευσης, σε διαφορετικούς servers, σε πολλά πανεπιστημιακά ιδρύματα. Ο web server έχει τη δυνατότητα να ανακαλεί με μεταβλητό αριθμό blocks, τμήμα από τις αποθηκευμένες πληροφορίες. Απαραίτητη κάθε φορά προϋπόθεση είναι: Ο συνολικός αριθμός των υφιστάμενων blocks, πρέπει να είναι ακέραιο πολλαπλάσιο του αριθμού των blocks που ανακαλούνται.

Πρόβλημα:

Να αναπτύξετε ένα πρόγραμμα σε μια από τις γλώσσες του ΙΟΙ το οποίο: Αφού διαβάζει το συνολικό αριθμό των υφιστάμενων blocks αποθηκευμένης πληροφορίας, θα επιστρέφει το πλήθος των δυνατών τρόπων ανάκτησής της και πόσα blocks μεταφέρονται κάθε φορά, με αύξουσα σειρά.

Αρχεία Εισόδου:

Τα αρχεία εισόδου με όνομα blocks.in είναι αρχεία κειμένου με ακριβώς έναν αριθμό N (15 ≤ N ≤ 999999999), τον αριθμό των συνολικώς υφιστάμενων blocks.

Αρχεία Εξόδου:

Τα αρχεία εξόδου με όνομα blocks.out είναι αρχεία κειμένου με την εξής δομή. Στην πρώτη γραμμή υπάρχει ένας ακέραιος αριθμός K που εκφράζει τον αριθμό των διαφορετικών τρόπων ανάκλησης των δεδομένων. Ακολουθούν K γραμμές σε κάθε μία από τις οποίες υπάρχει ένας αριθμός. Ο αριθμός των blocks που ανακαλούνται σε κάθε περίπτωση.

Παράδειγμα Αρχείων Εισόδου – Εξόδου
blocks.in blocks.out

15

3

1

3

5

Μορφοποίηση: Στην έξοδο, όλες οι γραμμές τερματίζουν με ένα newline χαρακτήρα.

Μέγιστος χρόνος εκτέλεσης: 15 sec.


Ενδεικτική λύση σε C
/* Αρσένης Γεράσιμος 2ο ΓΕΛ Μοσχάτου */

#include <stdio.h>
#include <stdlib.h>
#define MAX 70000

int comp(const void *i, const void *j) {
  return *(long *)i-*(long *)j;
}


int main() {
  FILE *fin=fopen("blocks.in", "r"), *fout=fopen("blocks.out", "w");
  long blocks[MAX], n, i, j;
  fscanf(fin, "%ld", &n);
  fclose(fin);
  for (i=2, j=0; i*i<=n; i++)
    if (n%i==0) { 
      blocks[j]=i; 
      j++; 
      if (i!=n/i) { 
        blocks[j]=n/i;
        j++; 
      } 
    }
  blocks[j]=1; j++;
  qsort(blocks, j, sizeof(long), comp);
  fprintf(fout, "%ld\n", j);
  for (i=0; i<j; i++)
    fprintf(fout, "%ld\n", blocks[i]);
  fclose(fout);
  return 0;
}

2ο Θέμα Τελικής Φάσης: Sonar

Οι Ελληνικές Ένοπλες Δυνάμεις με στόχο την προστασία των νησιών του ανατολικού Αιγαίου, ανέπτυξαν από τη δεκαετία του 70 συστήματα επιτήρησης ακτογραμμών με χρήση sonar. Ειδικά σε περιοχές στρατηγικής σημασίας, το δίκτυο sonar αναπτύχθηκε σε καρτεσιανή μορφή για μεγαλύτερη αποτελεσματικότητα. Το Σώμα Πληροφορικής, σε συνεργασία με το τμήμα Πληροφορικής και Τηλεπικοινωνιών του Πανεπιστημίου Αθηνών, ανέλαβε να αναπτύξει κατάλληλο λογισμικό, ώστε να υπάρχει ψηφιακή απεικόνιση του κάθε επιτηρούμενου πεδίου. Στο παρακάτω σχήμα φαίνεται ένα τέτοιο παράδειγμα:

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

Με έντονα μαύρα γράμματα εμφανίζεται η στάθμη του σήματος που λαμβάνεται κατά τη λήψη του εκπεμφθέντος ηχοσυρμού. Είναι φανερό ότι:

  1. Το σήμα είναι τόσο μικρότερης στάθμης όσο μακρύτερα εντοπιστεί στόχος. (Για σύστημα Ν Χ Ν sonar ο εγγύτερος στο sonar στόχος έχει σήμα στάθμης Ν και ο πλέον απομεμακρυσμένος 1).
  2. Όταν οι στόχοι κινούνται σε σειρά ή σε μέτωπο το αντίστοιχο sonar λαμβάνει μόνο σήμα από τον εγγύτερο στόχο. (Στο σχήμα μας, το δεύτερο οριζόντιο sonar λαμβάνει μόνο το σήμα από τον στόχο με συντεταγμένες [2, 4]).

Παρατήρηση: Στόχοι που είναι καλυμμένοι και κατά μέτωπο και κατά σειρά, δηλαδή εσωτερικοί σε νηοπομπή στόχοι, ΔΕΝ μπορούν να εντοπιστούν. (Σκοτεινή περιοχή στο παρακάτω σχήμα)

8                  
7                  
6 7   *            
5 7   *            
4 7   * *          
3                  
2                  
1                  
      5 5          
    1 2 3 4 5 6 7 8
Πρόβλημα:

Να αναπτύξετε ένα πρόγραμμα σε μια από τις γλώσσες του ΙΟΙ το οποίο: Αφού διαβάζει τις μη μηδενικές στάθμες σήματος που λαμβάνει κάθε sonar (πρώτα οριζόντιων και μετά κάθετων), θα επιστρέφει το πλήθος των στόχων που μπορούν να εντοπιστούν και ταξινομημένες με βάση τις τεταγμένες τους (οριζόντιος άξονας), τις θέσεις των στόχων. Στο παράδειγμά μας: [2, 4], [2, 5], [2, 6], [10, 10]. Σημειώνεται ότι στόχοι που μπορούν να εντοπιστούν και από τα οριζόντια και από τα κάθετα sonar (πχ. [2, 4] & [10, 10]) «κλειδώνονται» και καταγράφονται μόνο μια φορά.

Αρχεία Εισόδου:

Τα αρχεία εισόδου με όνομα sonar.in είναι αρχεία κειμένου με την εξής δομή: Στην πρώτη γραμμή έχουν έναν αριθμό Ν (10 ≤ Ν ≤ 99999) τις διαστάσεις (Ν Χ Ν) του επιτηρούμενου πεδίου. Στη δεύτερη γραμμή έχουν δύο αριθμούς Μ1, Μ2 (χωριζόμενους με ένα κενό) τον αριθμό των οριζόντιων και κάθετων sonar που ανίχνευσαν στόχο (Μ1, Μ2 ≤ Ν2). Στις επόμενες Μ1 γραμμές υπάρχουν με αύξουσα σειρά οι αριθμοί και η αντίστοιχη στάθμη σήματος, των οριζόντιων sonar που εντόπισαν στόχο. Στις επόμενες Μ2 γραμμές υπάρχουν με αύξουσα σειρά οι αριθμοί και η αντίστοιχη στάθμη σήματος, των κάθετων sonar που εντόπισαν στόχο. Σε όλα τα sonar ο αριθμός τους από τη στάθμη σήματος, χωρίζονται με ένα κενό.

Αρχεία Εξόδου:

Τα αρχεία εξόδου με όνομα sonar.out είναι αρχεία κειμένου με την εξής δομή. Στην πρώτη γραμμή υπάρχει ένας ακέραιος αριθμός Ν που εκφράζει τον αριθμό των στόχων που εντοπίστηκαν. Ακολουθούν N γραμμές σε κάθε μία από τις οποίες υπάρχουν οι συντεταγμένες των στόχων που εντοπίστηκαν, ταξινομημένες με βάση τις τεταγμένες τους. Στο παράδειγμά μας [2, 4], [2, 5], [2, 6], [10, 10]

Παράδειγμα Αρχείων Εισόδου – Εξόδου
sonar.in sonar.out

10
2 4
2 7
10 1
4 9
5 9
6 9
10 1

4
2 4
2 5
2 6
10 10

Μορφοποίηση: Στην έξοδο, όλες οι γραμμές τερματίζουν με ένα newline χαρακτήρα.

Μέγιστος χρόνος εκτέλεσης: 25 sec.


Ενδεικτική λύση σε C++
/* Παναγιωτάκος Γεώργιος 1ο ΓΕΛ Σπάρτης */
     
#include <iostream>
#include <fstream>
#include <list>

using namespace std;

int n,m1,m2;
class Pt 
{
  public:
  int x,y;
};

bool operator<(Pt a,Pt b)
{
  if(a.x==b.x)
    return a.y<b.y;
  else
    return a.x<b.x;
}

list<Pt> L;

int main()
{
  //input
  ifstream fin("sonar.in");
  ofstream fout("sonar.out");
  fin >> n >> m1 >> m2;
  //
  //main prog
  int u,i;
  Pt a;

  for(u=0;u<m1;u++)
  {
    fin >> a.x >> i;
    a.y=n+1-i;
    L.push_back(a);
  }
  for(u=0;u<m2;u++)
  {
    fin >> a.y >> i;
    a.x=n+1-i;
    L.push_back(a);
  }
  L.sort();
  Pt last;
  last.x=-1;
  last.y=-1;
  list<Pt>::iterator l;
  for(l=L.begin();l!=L.end();l++)
  {
    if((*l).x==last.x && (*l).y==last.y)
    { l=L.erase(l);
      l--;
      continue;
    }
    last.x=(*l).x;
    last.y=(*l).y;
  }
  fout << L.size() << "\n";
  for(l=L.begin();l!=L.end();l++)
    fout << (*l).x << " " << (*l).y << "\n";
  return 0;
}

3ο Θέμα Τελικής Φάσης: Ancient Code

Σε poster που ανάρτησαν δύο υποψήφιοι διδάκτορες αρχαιολογίας κατά τη διάρκεια του 12ου Πανελλήνιου Συνεδρίου Πληροφορικής (ΕΠΥ, Σάμος 2008) παρουσίασαν παλίμψηστο κώδικα της Ελληνιστικής περιόδου, που περιέγραφε τη λειτουργία του Μηχανισμού των Αντικυθήρων. Οι συνάδελφοι της Επιστημονικής Επιτροπής, προκειμένου να επιβεβαιώσουν το σημαντικό αυτό εύρημα, απευθύνθηκαν σε κορυφαίους επιστήμονες των θεωρητικών επιστημών. Βούληση της Επιστημονικής Επιτροπής ήταν το κείμενο να περάσει διαδοχικά από όλους τους ειδικούς με σκοπό να υπάρξει η εγκυρότερη γνώμη. Δυστυχώς όμως οι σχέσεις μεταξύ τους, δεν ήταν οι καλλίτερες δυνατές. Το κείμενο λοιπόν έπρεπε να μεταφερθεί από ειδικό σε ειδικό χωρίς αυτό να μπορεί να γίνει με οποιονδήποτε συνδυασμό. Ο τελευταίος πχ. που θα μελετήσει τον κώδικα, θα πρέπει να διατηρεί επικοινωνία με τον πρώτο, ώστε να μπορεί να το επιστρέψει εκεί από όπου ξεκίνησε.

Πρόβλημα:

Να αναπτύξετε πρόγραμμα σε μια από τις γλώσσες του ΙΟΙ το οποίο: αφού διαβάζει τις συσχετίσεις μεταξύ των επιστημόνων, θα καθορίζει μια τουλάχιστον δυνατή σειρά μεταβίβασης. Αν αυτό δεν μπορεί να συμβεί θα επιστρέφει την τιμή 0. Το κείμενο πρέπει να γυρίσει στον αρχικό παραλήπτη. (Είναι φανερό ότι μπορεί να υπάρχουν περισσότερες από μία λύσεις, οποιαδήποτε σωστή είναι απολύτως αποδεκτή).

Σημείωση 1: Κάθε επιστήμονας έχει τουλάχιστον έναν συνάδελφο με τον οποίο έχει καλές σχέσεις. Η σχέση αυτή είναι αμφίδρομη.

Σημείωση 2.: Ο κώδικας δεν μπορεί να μελετηθεί (περάσει) περισσότερες από μία φορές από τον ίδιο επιστήμονα.

Αρχεία Εισόδου:

Τα αρχεία εισόδου με όνομα code.in είναι αρχεία κειμένου με την εξής δομή: Στην πρώτη γραμμή υπάρχει ένας ακέραιος Ν (10 ≤ Ν ≤ 10000), ο αριθμός των συσχετίσεων μεταξύ των επιστημόνων. Οι επόμενες Ν γραμμές έχουν την παρακάτω δομή. Ο πρώτος αριθμός M (1 ≤ Μ ≤ 1000) κάθε γραμμής, είναι ο αύξων αριθμός ενός επιστήμονα. Ο δεύτερος αριθμός Κ (1 ≤ Κ ≤ 1000) είναι επίσης ο αύξων αριθμός ενός επιστήμονα, με τον οποίο διατηρεί καλές σχέσεις. Η σχέση αυτή είναι αμφίδρομη. (Οι δύο αριθμοί χωρίζονται με ένα κενό).

Αρχεία Εξόδου:

Τα αρχεία εξόδου με όνομα code.out είναι αρχεία κειμένου με την εξής δομή. Έχουν ακριβώς Π γραμμές (10 ≤ Π ≤ 1000), όπου Π ο αριθμός των επιστημόνων. (Άρα ο κώδικας θα περάσει μόνο μια φορά από κάθε επιστήμονα). Στην πρώτη γραμμή είναι ο αριθμός του επιστήμονα στον οποίο θα παραδοθεί πρώτα το κείμενο. Στην τελευταία γραμμή είναι ο αριθμός του τελευταίου επιστήμονα από τον οποίο θα περάσει το κείμενο πριν επιστρέψει στον πρώτο.

Παράδειγμα Αρχείων Εισόδου – Εξόδου
code.in code.out

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

1

2

3

4

5

6

7

8

9

10

(Η έξοδος είναι ενδεικτική και ΔΕΝ είναι η μόνη σωστή)

Μορφοποίηση: Στην έξοδο, όλες οι γραμμές τερματίζουν με ένα newline χαρακτήρα.
Μέγιστος χρόνος εκτέλεσης: 20 sec.


Ενδεικτική λύση σε C++

(Για τη λύση του συγκεκριμένου προβλήματος – κύκλος Hamilton - υπάρχουν περισσότερες από μία ορθές λύσεις. Ο χρόνος που απαιτείται για την εξαγωγή των αποτελεσμάτων, εξαρτάται από τα test cases. Επειδή για τα συγκεκριμένα test cases κανένας μαθητής δεν έδωσε λύση που να λύνει τουλάχιστον το 50% αυτών εντός χρόνου, δίνεται στη δημοσιότητα μια από τις δυνατές λύσεις που για τα συγκεκριμένα tests, απαιτεί χρόνο πολύ μικρότερο από 20 sec για πάνω από το 50% των tests)

/* Dimitris Fotakis
   Nikolaos S. Papaspyrou */
  
#define DEBUG
#ifdef DEBUG
#define debug(...) fprintf(stderr, __VA_ARGS__)
#else
#define debug(...) do ; while(0)
#define NDEBUG
#endif
 
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <time.h>
#include <sys/types.h>
#define NILL (-1)
#define INF ((long) (LONG_MAX))
#define NONE (-1)
#define VISITED 0
#define UNVISITED 1
#define EXPLORED 2

  
void randomize ()
{
  time_t t1;
  (void) time(&t1);
  srand((long) t1); /* use time in seconds to set the seed */
}

/* Implements a FIFO queue for use with BFS */
typedef struct _elem {
  int id;
  struct _elem *next;
} elem;
elem *head = NULL, *tail = NULL;


void addToQueue (int v)
{
  elem *last;
  if ((last = (elem *)malloc(sizeof(elem))) == NULL) {
    fprintf(stderr, "Out of memory!\n");
    exit(1);
  }
  last->id = v;
  last->next = NULL;
  if (tail != NULL) tail->next = last;
  tail = last;
  if (head == NULL) head = last;
}


int extractFromQueue ()
{
  elem *first;
  int res;
  if (head == NULL) return(NILL);
  first = head;
  res = first->id;
  head = first->next;
  if (head == NULL) tail = NULL;
  free(first);
  return res;
}

/* Data type definitions for adjacency list */
typedef struct _edge {
  int id;
  struct _edge *next;
} Edge;

typedef struct _node {
  Edge *head;
  Edge *tail;
  int prevInCycle;
  int nextInCycle;
  int inCycle;
  int degree;
} Node;

typedef Node * List;

/* Creates an edge */

Edge *initEdge (int id)
{
  Edge *e;
  if ((e =(Edge *)malloc(sizeof(Edge))) == NULL) {
    fprintf(stderr, "Out of memory!\n");
    exit(1);
  }
  e->next = NULL;
  e->id = id;
  return e;
}

/* Reads a graph from filename and creates its adjacency list */
/* Initializes N (#vertices) and M (#edges) and returns the list */

List readGraph(FILE *fp, int *N, int *M)
{
  Edge *lastV1, *lastV2;
  int i, n = 0, v1, v2;
  List G;
  fscanf(fp, "%d\n", M);
  if ((G = (List) malloc((*M)*sizeof(Node))) == NULL) {
    fprintf(stderr, "Out of memory!\n");
    exit(1);
  }
  for (i = 0; i < *M; i++) {
    G[i].head = G[i].tail = NULL;
    G[i].nextInCycle = G[i].prevInCycle = NONE;
    G[i].degree = G[i].inCycle = 0;
  }
  for (i = 0; i < *M; i++) {
    fscanf(fp, "%d %d\n", &v1, &v2);
    if (n < v1) n = v1;
    if (n < v2) n = v2;
    v1--; v2--;
    lastV1 = initEdge(v2); G[v1].degree++;
    lastV2 = initEdge(v1); G[v2].degree++;
    if (G[v1].head == NULL)
      G[v1].head = G[v1].tail = lastV1;
    else
      G[v1].tail = G[v1].tail->next = lastV1;
    if (G[v2].head == NULL)
      G[v2].head = G[v2].tail = lastV2;
    else
      G[v2].tail = G[v2].tail->next = lastV2;
  }
  *N = n;
  if ((G = (List) realloc(G, n*sizeof(Node))) == NULL) {
    fprintf(stderr, "Error in realloc!\n");
    exit(1);
  }
  return G;
}


bool degree_lt_2 (List G, int N)
{
  int i;
  for (i = 0; i < N; i++)
    if (G[i].degree < 2)
      return true;
  return false;
}


bool not_connected (List G, int N)
{
  int s, cc = 0, v;
  Edge *e;
  int *m;
  if ((m = (int *) malloc(N*sizeof(int))) == NULL) {
    fprintf(stderr, "Out of memory!\n");
    exit(1);
  }
  for (s = 0; s < N; s++)
    m[s] = UNVISITED;
  for (s = 0; s < N; s++) {
    if (m[s] == EXPLORED) continue;
    addToQueue(s);
    m[s] = VISITED; cc++;
    while ((v = extractFromQueue()) != NILL) {
      m[v] = EXPLORED;
      for (e = G[v].head; e != NULL; e = e->next)
        if (m[e->id] == UNVISITED) {
          addToQueue(e->id);
          m[e->id] = VISITED;
        }
    }
  }
  return cc > 1;
}


int extension_rotation (List G, int N)
{
  long iter, maxIter = (long) (((double) N)*(pow(log((double)N), 4)));
  int inVert = 1, cur, last, rotv, i, k, ofs, tmp, first;
  Edge *p;
  cur = rand() % N;
  G[cur].inCycle = 1;
  first = cur;
  for (iter=0; inVert <= N && iter < maxIter; iter++) {
    /* complete a Hamiltonian path to a cycle */
    if (inVert == N)
      for (p = G[cur].head; p != NULL; p = p->next)
        if (G[p->id].prevInCycle == NONE) {
          G[p->id].prevInCycle = cur;
          return(inVert+1);
        }
    /* extension phase */
    for (p = G[cur].head, k = 0; !k && p != NULL; p = p->next)
      if (G[p->id].inCycle == 0) {
        G[p->id].inCycle = 1;
        G[p->id].prevInCycle = cur;
        G[cur].nextInCycle = p->id;
        cur = p->id;
        inVert++;
        k = 1;
      }
    /* rotation phase */
    if (!k) {
      do {
        ofs = (rand() % G[cur].degree);
        for (p = G[cur].head; ofs > 0; ofs--)
          p = p->next;
        rotv = p->id;
      } while (rotv == G[cur].prevInCycle);
      if (rotv == first) {
        first = G[rotv].nextInCycle;
        G[rotv].nextInCycle = NONE;
        G[rotv].prevInCycle = cur;
        G[cur].nextInCycle = rotv;
        G[first].prevInCycle = NONE;
        cur = rotv;
      }
      else {
        last = G[rotv].nextInCycle;
        G[rotv].nextInCycle = cur;
        G[cur].nextInCycle = rotv;
        i = G[last].nextInCycle;
        G[last].nextInCycle = NONE;
        G[last].prevInCycle = i;
        do {
          tmp = G[i].nextInCycle;
          G[i].nextInCycle = G[i].prevInCycle;
          G[i].prevInCycle = tmp;
          i = tmp;
        } while (i != rotv);
        cur = last;
      }
    }
  }
  return inVert;
}


int main ()
{
  FILE * fin = fopen("code.in", "rt");
  FILE * fout = fopen("code.out", "wt");
  int N, M, res, i;
  int iter = 0, maxIter = 40;
  List G;
  assert(fin != NULL);
  assert(fout != NULL);
  G = readGraph(fin, &N, &M);
  if (degree_lt_2(G, N) || not_connected(G, N))
    fprintf(fout, "0\n");
  else {
    randomize();
    do {
      if ((res = extension_rotation(G, N)) == N+1) break;
      iter++;
      for (i = 0; i < N; i++) {
        G[i].nextInCycle = G[i].prevInCycle = NONE;
        G[i].inCycle = 0;
      }
    } while (iter < maxIter);
    if (res == N+1) {
      fprintf(fout, "1\n");
      for (i = G[0].nextInCycle; i != 0; i = G[i].nextInCycle)
        fprintf(fout, "%d\n", i+1);
    }
    else
      fprintf(fout, "0\n");
  }
  fclose(fin);
  fclose(fout);
  return 0;
}