Informatică, întrebare adresată de ionutg38, 9 ani în urmă

Zoli și D’Umbră s-au pierdut din nou prin labirintul cu n x n camere dispuse pe n linii și n coloane. De această dată, amândoi se află în camera (1, 1). A mai trecut de ultima dată și cateva lucruri s-au schimbat. Ei îl au acum la dispoziție pe Memobot, un roboțel controlat prin telecomandă care poate primi secvențe de comenzi. Când roboțelul primeste o secvență de comenzi, acesta va respecta fiecare comandă din secvență, apoi va aștepta o nouă comandă.

Din păcate pentru ei, Dr. Boom s-a plictisit să trimită Boom Bots (niște roboței care explodează singuri) să-i enerveze pe eroii din Azeroth. Așadar, acesta îi poziționează în câteva camere din labirint și care vor exploda când se vor afla în cameră cu înca cineva.

Acum Zoli și D’Umbră vor trebui să îl trimită pe Memobot pentru a curăța drumul până la ieșirea aflată în camera (n, n). Ajutați-i să iasă din labirint pe drumul cel mai scurt parcurs de Memobot! (Drumul cel mai scurt este, bineînțeles, cel ce conține un număr minim de secvențe de comenzi)

Date de intrare
Fișierul de intrare labirint2.in conține pe prima linie numerele n (dimensiunea labirintului), b (numărul de Boom Bots pe care Dr. Boom îi poziționează în labirint), s (numărul de secvențe de comenzi) și k (numărul de comenzi din fiecare secvență).

Pe următoarele b linii se află câte o pereche de numere naturale x și y reprezentând faptul că Dr. Boom a trimis un Boom Bot în camera aflată la coordonatele (x, y).

Pe următoarele s linii se află cate k litere din mulțimea {'U', 'D', 'L', 'R'} care reprezintă direcția spre care se va deplasa Memobot în secvență. (U – Sus, D – Jos, L – Stânga, R – Dreapta).

Date de ieșire
Fișierul de ieșire labirint2.out va conține pe prima linie numărul S, reprezentând numărul minim de secvențe de comenzi pe care Memobot trebuie să le primească.

Restricții și precizări
1 ≤ n ≤ 400
1 ≤ b ≤ n * n
1 ≤ k, s ≤ 10
Ordinea comenzilor din fiecare secvență nu poate fi schimbată!
Memobot poate trece de două ori prin aceeași cameră.
Pentru 30% din teste, k = 1, s = 4 și secvențele sunt diferite între ele. (Memobot va putea merge pe direcțiile simple: Dreapta, Stânga, Sus și Jos)
Dacă Memobot primește o secvență de comenzi care îl conduc spre o cameră inexistentă (pe linia/coloana 0 sau n + 1), atunci Memobot nu va executa secvența.
Dacă cel puțin 2 Boom Bots se află într-o cameră, aceștia vor exploda înainte ca Memobot să pornească.
Dacă nu există nici un drum prin care Memobot să ajungă în camera (n, n), atunci se va afișa mesajul ”Imposibil!”
Personajul este D’Umbră și nu Dumbră, și Dr. Boom este sigur de acest lucru.



Exemplu
labirint2.in

4 3 4 2
3 2
3 3
4 1
D R
D L
U R
D D
labirint2.out

4
Explicație
Comenzile sunt, în această ordine: (D, R), (U, R), (D, R), (D, D)


Utilizator anonim: eroii din Azeroth? Pe bune?...
blindseeker90: m-am straduit sa fac un cod simplu, dar nu mi-a fost posibil. Trebuie sa cunosti backtracking si structuri de date ca sa poti trece prin aceasta rezolvare. In fereastra de comanda o sa iti apara si caile. Solutia a fost testata doar pentru matrici mici, habar nu am cum va functiona pentru matrici ceva mai mari.
ionutg38: Multumesc! A mers doar pe exemplu. In rest a depasit limita de timp (1 sec./test)
ionutg38: Indicații de rezolvare


Problema se rezolvă cu ajutorul algoritmului lui Lee, însă în loc să avem 2 vectori care reprezintă noile direcții, vom avea 2 matrici și vom verifica pentru fiecare secvență de comenzi în parte dacă roboțelul se poate deplasa pe poziția nouă.
blindseeker90: Care este nivelul tau acuma? Stii sa folosesti lanturi de pointeri? Algoritmul lui Lee de obicei este implementat cu structuri de pointeri.
ionutg38: Da, pe bune
ionutg38: da, stiu

Răspunsuri la întrebare

Răspuns de blindseeker90
7
#include <iostream>
#include <fstream>
#include <limits.h>
using namespace std;

const int MAX=100;
const int MAX_BOMBE=400*400;
const int MAX_DIM=400; 
int b,n,s,k,nr_solutii,nr_vizite;

char comenzi[10][10],solutii[MAX][10];
int lungime_solutii[MAX],bombe[MAX_BOMBE][2];

struct pozitie{  
int x;
int y;
}vizitat[MAX_BOMBE];

//functie pentru a verifica perechea x,y daca se afla deja in vectorul vizitat
int deja_vizitat(int x,int y){
int i;
for(i=1;i<nr_vizite;i++){
if(vizitat[i].x==x&&vizitat[i].y==y){
return 1;
}
}
return 0;
}
//-----------------------------------------------------------
//functii pentru eliminarea bombelor duplicat
void copiaza_elem(int a[MAX_BOMBE][2],int b[MAX_BOMBE][2],int n){
int i;
for(i=0;i<n;i++){
b[i][0]=a[i][0];
b[i][1]=a[i][1];
}
}

void elimina_duplicate(int v[],int nr_duplicate){
int i,j,bombe_sing[400*400][2],este_in_sir,nr_sing=0;
for(j=0;j<b;j++){
este_in_sir=0;
for(i=0;i<=nr_duplicate;i++){
if(j==v[i]){
este_in_sir=1;
break;
}
}
if(este_in_sir==0){
bombe_sing[nr_sing][0]=bombe[j][0];
bombe_sing[nr_sing][1]=bombe[j][1];
nr_sing++;
}
}
copiaza_elem(bombe_sing,bombe,nr_sing);

}
void explodeaza_mini_bot(){
int i,j,v[b],nr_duplicate=0,explodeaza;

for(i=0;i<b-1;i++){
explodeaza=0;
for(j=i+1;j<b;j++){
if(bombe[j][0]==bombe[i][0]&&bombe[j][1]==bombe[i][1]){
v[nr_duplicate]=j;
nr_duplicate++;
explodeaza=1;
}
}
if(explodeaza==1){
v[nr_duplicate]=i;
elimina_duplicate(v,nr_duplicate);
break;
}
}
if(explodeaza==1){
b=b-nr_duplicate-1;
explodeaza_mini_bot();
}

}
//-------------------------------------------------------------------

//-----------------------------------------------------------------

//backtracking functions
int valid(int x,int y){
int i;
if(x<1||x>n||y<1||y>n){
return 0;
}
for(i=0;i<b;i++){
if(bombe[i][0]==x&&bombe[i][1]==y){
return 0;
}
}
return 1;
}
int solutie(int x,int y){
return (x==n&&y==n);
}

void afisare(int nr){
int i,j;
for(i=1;i<=nr;i++){
cout<<"(";
for(j=0;j<k;j++){
if(j==k-1){
cout<<solutii[i][j]<<")";
}
else{
cout<<solutii[i][j]<<",";
}
}
cout<<" ";
}
cout<<endl;
}

void bk(int nr){
int x0,y0,control=0;
if(nr==1){
vizitat[nr].x=1;
vizitat[nr].y=1;
nr_vizite++;
}
x0=vizitat[nr].x;
y0=vizitat[nr].y;
int i,j,x1,y1,x2,y2,validare_miscare;
//cout<<x0<<" "<<y0<<" Primul backtrack!"<<endl;
for(i=0;i<s;i++){
validare_miscare=1;
x1=vizitat[nr].x;
y1=vizitat[nr].y;
//cout<<nr<<" si "<<i<<" si "<<vizitat[nr].x<<" "<<vizitat[nr].y<<endl;
for(j=0;j<k;j++){
switch(comenzi[i][j]){
case 'L':
x2=x1;
y2=y1-1;
break;
case 'R':
x2=x1;
y2=y1+1;
break;
case 'U':
y2=y1;
x2=x1-1;
break;
case 'D':
y2=y1;
x2=x1+1;
break;

default:
cout<<"Caracter invalid!";
}
if(valid(x2,y2)==0||deja_vizitat(x2,y2)==1){
//cout<<nr<<" si "<<i<<" "<<x2<<" "<<y2<<" "<<"Miscare invalida "<<j+1<<" "<<comenzi[i][j]<<endl;
validare_miscare=0;
break;
}
x1=x2;
y1=y2;

//cout<<nr<<" si "<<i<<" "<<x1<<" "<<y1<<" Miscare "<<j+1<<" "<<comenzi[i][j]<<" "<<endl;
solutii[nr][j]=comenzi[i][j];
}
if(validare_miscare==1){
x0=x1;
y0=y1;
//cout<<x0<<" "<<y0<<" "<<nr<<" "<<nr_solutii<<" Valid";
//afisare(nr);
//cout<<endl;
if(solutie(x0,y0)){
afisare(nr);
lungime_solutii[nr_solutii]=nr;
nr_solutii++;
return;

}
else {
// else if(deja_vizitat(x0,y0)==0){
//cout<<x0<<" "<<y0<<" "<<nr+1<<" Intra in backtrack!"<<endl;
vizitat[nr+1].x=x0;
vizitat[nr+1].y=y0;
nr_vizite++;
bk(nr+1);
}
}

}
}


int main(){
ifstream f("labirint2.in");
ofstream of("labirint2.out");
int i,j,min=INT_MAX;
f>>n>>b>>s>>k;
for(i=0;i<b;i++){
f>>bombe[i][0]>>bombe[i][1];
}
explodeaza_mini_bot();
for(i=0;i<s;i++){
for(j=0;j<k;j++){
f>>comenzi[i][j];
}
}
nr_vizite=1;
bk(nr_vizite);
for(i=0;i<nr_solutii;i++){
if(lungime_solutii[i]<min){
min=lungime_solutii[i];
}
}
of<<min;

return 0;
}

ionutg38: Indicații de rezolvare


Problema se rezolvă cu ajutorul algoritmului lui Lee, însă în loc să avem 2 vectori care reprezintă noile direcții, vom avea 2 matrici și vom verifica pentru fiecare secvență de comenzi în parte dacă roboțelul se poate deplasa pe poziția nouă.
ionutg38: A functionat doar pe exemplu. In rest, a depasit limita de timp (1 secunda/test)
Alte întrebări interesante