Pagini: [1]   În jos
  Imprimă  
Ajutor Subiect: Robot  (Citit de 1783 ori)
0 Utilizatori şi 1 Vizitator pe acest subiect.
TheNechiz
De-al casei
***

Karma: 30
Deconectat Deconectat

Mesaje: 145



Vezi Profilul
« : Februarie 27, 2013, 17:19:56 »

Problemă: http://img24.imageshack.us/img24/2057/scan0002om.jpg
Am rezolvat problema,dar nu cred că soluția mea este optimă.

Folosesc o coadă.În fiecare nod al cozii memorez: linia și coloana pe care mă poziționez,indicele elementului din prima linie de pe care a plecat robotul,energia pe care o are robotul acum.
Dacă am ajuns pe linia n și robotul mai are energie atunci consider valid indicele de unde a plecat robotul.
La final, dacă am indici valizi îi scriu în fișier,altfel tipăresc -1.

Cod:
# include <fstream>
# include <cstdlib>
# define dim 203
# define lim 41412
using namespace std;

struct
{
    short int j,x,y;
    int e;
}v[lim];

short int c[dim][dim],n,m,ener,i,j;
int ind = -1;
bool p[dim] = {false};

void Citeste()
{
    ifstream in("robot.in");
    in >> ener >> n >> m;
    for( i = 1 ; i <= n ; ++i )
        for( j = 1 ; j <= m ; ++j )
    {
        in >> c[i][j];
        if( i == 1 )
        {
            ++ind;
            v[ind].j = j;
            v[ind].x = i;
            v[ind].y = j;
            v[ind].e = ener;
        }
    }
}

void Drum()
{
    short int lin,col,g;
    int e1;
    for( i = 0 ; i <= ind ; ++i )
    {
        lin = v[i].x;
        col = v[i].y;
        g = v[i].j;
        e1 = v[i].e;
        if( lin == n && e1 > 0 )
            p[g] = true;
        if( lin+1 <= n )
        {
            if( e1 - abs(c[lin][col] - c[lin+1][col]) > 0 )
            {
                ++ind;
                v[ind].x = lin+1;
                v[ind].y = col;
                v[ind].j = g;
                v[ind].e = e1 - abs(c[lin][col] - c[lin+1][col]);
            }
            if( e1 - abs(c[lin][col] - c[lin+1][col+1]) > 0 && col+1 <= m )
            {
                ++ind;
                v[ind].x = lin+1;
                v[ind].y = col+1;
                v[ind].j = g;
                v[ind].e = e1 - abs(c[lin][col] - c[lin+1][col+1]);
            }
            if( e1 - abs(c[lin][col] - c[lin+1][col+1]) > 0 && col-1 >= 1 )
            {
                ++ind;
                v[ind].x = lin+1;
                v[ind].y = col-1;
                v[ind].j = g;
                v[ind].e = e1 - abs(c[lin][col] - c[lin+1][col-1]);
            }
        }
    }
}

void Tipar()
{
    bool ok = false;
    ofstream out("robot.out");
    for( i = 1 ; i <= m ; ++i )
        if( p[i] == true )
        {
            ok = true;
            out << i << ' ';
        }
    if( !ok ) out << "-1";
    out.close();
}

main()
{
    Citeste();
    Drum();
    Tipar();
}

Voi cum ați rezolva această problemă ?  Smile
Memorat
fdproxy
Strain
*

Karma: 10
Deconectat Deconectat

Mesaje: 30



Vezi Profilul
« Răspunde #1 : Februarie 28, 2013, 01:02:35 »

- Cerinta nu pomeneste nimica de optimal (si cred ca nu aveti cunostinele necesare).
- Nu am inteles la ce foloseste "coada" (si nici de ce ii zici "coada").
- Ce faci daca drumul pe care esti consuma toata energia dar exista altul bun (cu acelasi punct de pornire)?
- Foloseste comentarii.
- bool p[dim] = {false}; initializeaza primul element, nu tot vectorul. Asta a fost intentia?
- main fara int in fata violeaza standardul curent.
Memorat
TheNechiz
De-al casei
***

Karma: 30
Deconectat Deconectat

Mesaje: 145



Vezi Profilul
« Răspunde #2 : Februarie 28, 2013, 08:31:37 »

-Cunoştinţe necesare pentru ce ? Eu înţeleg prin soluţie optimă: o soluţie care consumă cât mai puţină memorie şi are un timp de execuţie cât mai mic.
-Ştiu că o coadă este o structură de date,un caz particular de listă care funcţionează pe principiul FIFO (first in – first out, primul intrat este primul servit).E ceva greşit dacă îi zic "coadă" ? Îi spun aşa de când am învăţat algoritmul lui Lee ( implementat cu o coadă ).Cred că ce am făcut mai sus seamănă cu algoritmul lui Lee,deşi am o mică suspiciune în ceea ce îl priveşte pe v[ i ].e.
-Merg pe toate drumurile posibile.
-Pe viitor o să folosesc comentarii.
-bool p[dim] = {false}; ştiu că variabilele globale sunt iniţializate cu 0.Voiam să mă asigur că fiecare element al vectorului are valoare "false".Acum văd că am făcut o greşeală gravă.
-main nu credeam că e o greşeală gravă.Deşi acolo am un warning.O să foloseasc int main().

Problema asta am primit-o la olimpiadă şi mă întrebam dacă nu cumva m-am complicat prea mult.Nu am altă idee de rezolvare,dar presupun că există o soluţie mai simplă,care să consume mai puţină memorie şi să aibă un timp de execuţie mai bun.
« Ultima modificare: Februarie 28, 2013, 09:09:04 de către Birisan Razvan » Memorat
fdproxy
Strain
*

Karma: 10
Deconectat Deconectat

Mesaje: 30



Vezi Profilul
« Răspunde #3 : Martie 01, 2013, 00:04:38 »

Felicitari pentru participarea la olimpiada.

- [...puţină memorie şi are un timp de execuţie cât mai mic.] Inainte de orice, trebuie sa te preocupe corectitudinea rezultatului.
- [...E ceva greşit dacă îi zic "coadă" ?] Nu; e foarte bine, doar ca nu am vazut-o. Nu-mi aduc aminte de algoritm; au trecut ceva ani de cand am terminat scoala.
- [Pe viitor o să folosesc comentarii.] Comentariile te ajuta.
- [...am făcut o greşeală gravă.] N-as zice.
- [...nu credeam că e o greşeală gravă] N-ai putea compila codul pe compilatoare mai noi.
- M-am uitat inca o data la programel si nu am inteles ce urmaresti, asa ca l-am compilat. Pentru setul de mai jos am obtinut: 1 2 3 4. Este corect?
100 4 4
 10  80  60  90
100 100 100  50
200 100 100  60
300 500 200 100

Memorat
TheNechiz
De-al casei
***

Karma: 30
Deconectat Deconectat

Mesaje: 145



Vezi Profilul
« Răspunde #4 : Martie 01, 2013, 08:35:36 »

Citat
-[...puţină memorie şi are un timp de execuţie cât mai mic.] Inainte de orice, trebuie sa te preocupe corectitudinea rezultatului.
De acord. Smile

Citat
- M-am uitat inca o data la programel si nu am inteles ce urmaresti, asa ca l-am compilat. Pentru setul de mai jos am obtinut: 1 2 3 4. Este corect?
100 4 4
 10  80  60  90
100 100 100  50
200 100 100  60
300 500 200
Este corect. Cool
Pe mine mă îngrijorează testele mari,sunt greu de verificat cu creionul pe hârtie și mi-e frică să nu depășească numărul de elemente al cozii.

Fiecare pas posibil al robotului este memorat în coadă și pe mine mă interesează dacă la pasul pe linia n mai are energie( > 0 ).  Thumb up
Memorat
fdproxy
Strain
*

Karma: 10
Deconectat Deconectat

Mesaje: 30



Vezi Profilul
« Răspunde #5 : Martie 01, 2013, 13:05:40 »

In cazul asta, felicitari. Implementarea pare a fi foarte simpla. Ce faci acolo semana cu “breadth-frist search”. O sa revad enuntul, daca gasesc timp.

Cel mai simplu ar fi sa intrerupi executia, daca depasesti limitele, si sa afisezi un mesaj de eroare; sau poti folosi coada standard <queue> (mai lenta).

...

Am gasit ceva timp si am implementat cum m-am priceput. Nu am participat la vreun concurs, asa ca nu prea stiu care sunt cerintele. Se pare ca este incurajata folosirea variabilelor globale si a numelor criptice. Copiaza codul pe calculatorul tau si vezi ce iese.

Cod:
#include <time.h>
#include <fstream>
#include <iostream>
using namespace std;

// i este indexul randului; intodeauna
// j este indexul coloanei; intodeauna

// energia maxima
#define EMAX 30000

// numarul maxim de randuri
#define RMAX 200

// numarul maxim de coloane
#define CMAX 200

// energia intiala
int p;

// numarul de randuri
int n;

// numarul de coloane
int m;

// tabla de joc
int c[RMAX][CMAX];

// celulele vizitate
char v[RMAX][CMAX];

// starea robotului
struct t_state
{
  int r; // rand
  int c; // coloana
  int ec; // energie celula
  int er; // energie robot
  void set( int ar, int ac, int aec, int aer ) { r = ar; c = ac; ec = aec; er = aer; }
};

// coada de stari intermediare
t_state q[RMAX*CMAX]; // datele
int dq; // indexul de extrage (deque)
int eq; // indexul de inserare (enque)

// solutii
int s[CMAX];
int ns; // numar solutii

//
int global_bytes_count()
{
  return sizeof( p ) + sizeof( n ) + sizeof( m ) +
    sizeof( c ) +
    sizeof( v ) +
    sizeof( q ) + sizeof( dq ) + sizeof( eq ) +
    sizeof( s ) + sizeof( ns );
}

//
bool read()
{
  ifstream is( "robot.in" );
  if ( ! is )
    return false;

  if ( ! ( is >> p >> n >> m ) )
    return false;

  for ( int i = 0; i < n; ++i )
    for ( int j = 0; j < m; ++j )
      if ( ! ( is >> c[i][j] ) )
        return false;

  return true;
}

//
bool write()
{
  ofstream os( "robot.out" );
  if ( ! os )
    return false;

  if ( ns < 1 )
  {
    if ( ! ( os << -1 ) )
      return false;
  }
  else
  {
    for ( int i = 0; i < ns; ++i )
      if ( ! (os << s[i] << ' ' ) )
        return false;
  }

  return true;
}

// find_path implementeaza algoritmul "breadth-first search"
// cu o definitie alternativa a adiacentei data de consumul de energie:
// daca consumul este prea mare, celula nu este adiacenta
// (vezi Introduction to Algorithms, Cormen et alii)
bool find_path( int j )
{
  // reseteaza celulele vizitate
  memset( v, 0, sizeof(v) );

  // reseteaza coada
  dq = eq = 0;

  // adauga pozitia initiala
  q[eq++].set( 0, j, c[0][j], p );

  // marcheaza pozitia initiala
  v[0][j] = 1;
 
  // cat timp coada nu e goala
  while ( eq - dq > 0 )
  {
    // extrage din coada
    int tq = dq++;

    // daca am ajuns la ultimul rand
    if ( q[tq].r >= n - 1 )
      return true;

    // examineaza celulele adiacente
    int i = q[tq].r + 1; // randul adiacent
    int pc = ( q[tq].c <= 0 ) ? 0 : -1; // prima coloana relativ la pozitia curenta
    int uc = ( q[tq].c <= m - 2 ) ? 1 : 0; // ultima coloana relativ la pozitia curenta
    for ( int k = pc; k <= uc; ++k ) // coloanele adiacente relativ la coloana curenta
    {
      // coloana adiacenta
      int j = q[tq].c + k;
     
      // care ar fi energia robotului daca s-ar muta pe celula adiacenta
      int er = q[tq].er - abs( c[i][j] - q[tq].ec );
      if ( er <= 0 )
        continue; // toata energia ar fi consumata: celula nu e "adiacenta"

      // celula adiacenta
     
      // daca celula nu este vizitata
      if ( ! v[i][j] )
      {
        // insereaza in coada
        q[eq++].set( i, j, c[i][j], er );
        // marcheaza
        v[i][j] = 1;
      }
    }
  }

  // nu a fost gasit niciun drum
  return false;
}

//
void run()
{
  // initializeaza numarul de solutii
  ns = 0;

  // cauta drumul pentru fiecare coloana
  for ( int j = 0; j < m; ++j )
    if ( find_path( j ) )
      s[ns++] = j + 1;
}

//
void print_gmem_info()
{
#ifndef NDEBUG
  cout << "Memorie globala consumata: " << double( global_bytes_count() ) / 1024 / 1024 << " MB" << endl;
#endif
}

// numarul de executii pentru benchmark
#define XMAX 100000

// afiseaza durata total a executiilor
#define BENCHMARK

int main()
{
  print_gmem_info();

  if ( ! read() )
  {
    cerr << "Eroare la citire";
    return -1;
  }

#ifdef BENCHMARK
  clock_t t0 = clock();
  for ( int k = 0; k < XMAX; ++k )
#endif

    run();

#ifdef BENCHMARK
  clock_t d = clock() - t0;
  cout << "Durata pentru " << XMAX << " executii: " << double(d)/CLOCKS_PER_SEC << "s" << endl;
#endif

  if ( ! write() )
  {
    cerr << "Eroare la scriere";
    return -2;
  }

  return 0;
}
« Ultima modificare: Martie 01, 2013, 21:03:49 de către fdproxy » Memorat
TheNechiz
De-al casei
***

Karma: 30
Deconectat Deconectat

Mesaje: 145



Vezi Profilul
« Răspunde #6 : Martie 04, 2013, 21:54:52 »

O implementare destul de interesantă.O să mă mai uit pe ea,acum doar am aruncat un ochi.

PS: Mersi pentru ajutorul la erorile de sintaxă.
Memorat
Pagini: [1]   În sus
  Imprimă  
 
Schimbă forumul:  

Powered by SMF 1.1.19 | SMF © 2006-2013, Simple Machines