Rezolvare completă PbInfo #1066 AI

Institutul Naţional de Robotică Avansată realizează o serie de teste ultimei generaţii de roboţi inteligenţi proiectaţi de specialiştii acestuia. Sistemul de testare se bazează pe o reţea de senzori formată din n segmente egale dispuse orizontal şi n segmente egale dispuse vertical. Distanţa între două segmente alăturate orizontale, respectiv verticale este de 1 metru. Fiecare segment orizontal este în contact cu fiecare segment vertical. Denumim nod un punct în care un segment orizontal şi unul vertical vin în contact. Segmentele sunt numerotate: cele orizontale de sus în jos începând de la 1 iar cele verticale de la stânga la dreapta începând de la 1.

Un nod va fi identificat prin două numere: primul reprezintă numărul segmentului orizontal iar al doilea numărul segmentului vertical care vin în contact în respectivul nod.

Într-unul dintre nodurile reţelei se află o ţintă. În alte două noduri se află câte o sursă ce emite o rază laser. O astfel de sursă emite raza într-o singură direcţie. Raza laser are o grosime neglijabilă. Cele două surse sunt astfel orientate încât raza emisă de fiecare “loveşte” ţinta. Cele două noduri în care sunt plasate sursele sunt astfel alese încât cele două raze nu se intersectează decât în nodul unde se află ţinta.

În alte două noduri ale reţelei se află câte un robot. Fiecare robot se poate deplasa dintr-un nod în cele vecine (cele aflate sus, jos, în stânga şi în dreapta), dar fără să iasă din cadrul reţelei. Roboţii se deplasează cu 1 m/secundă.

Se efectuează experimente în care roboţii sunt programaţi să se deplaseze prin reţea cu scopul de a proteja ţinta faţă de cele două raze laser. Un robot poate proteja ţinta fie ocupând nodul unde se află sursa, fie ocupând un nod prin care trece raza laser în drumul de la sursă către ţintă (razele laser nu “ocolesc” roboţii). Dimensiunea roboţilor este atât de mică încât, în acest al doilea caz, ei protejează ţinta faţă de raza laser doar când nodurile unde sunt sursa, ţinta şi robotul sunt coliniare iar robotul este între sursă şi ţintă. În momentul în care un robot ajunge într-un nod unde protejează ţinta faţă de una dintre raze, el se poate opri sau poate să îşi continue deplasarea. Dacă îşi continuă deplasarea astfel încât noua poziţie ocupată de acel robot şi poziţiile ţintei şi sursei nu mai sunt coliniare, atunci acel robot nu mai protejează ţinta. Din modul în care sunt alese poziţiile nodurilor pentru ţintă şi sursele laser rezultă că nu există nicio poziţie în care un robot să protejeze simultan ţinta faţă de ambele raze.

Fiecare robot este dotat cu o reţea neuronală şi poate învăţa din experimentele anterioare pe unde să se deplaseze. Pentru a mări capacitatea de adaptare a roboţilor, în k noduri ale reţelei sunt aşezate obstacole care fac ca roboţii să nu poată trece prin nodurile respective. Deoarece obstacolele folosite sunt transparente, razele laser pot trece prin acestea fără a le fi afectată intensitatea sau direcţia. Două sau mai multe obstacole dispuse pe acelaşi segment, în noduri alăturate, formează un zid. Lungimea unui zid este egală cu numărul de obstacole din care este alcătuit.

Cerinţă

1) Determinaţi lungimea maximă a unui zid.
2) Determinaţi numărul minim de secunde în care cei doi roboţi pot proteja ţinta faţă de cele două raze laser.

Date de intrare

Fișierul de intrare ai.in conține

  • pe prima linie o valoare naturală n, reprezentând numărul segmentelor ce compun reţeaua;
  • pe a doua linie cinci perechi de valori naturale separate prin câte un spaţiu T1 T2 S1 S2 S3 S4 R1 R2 R3 R4 cu următoarea semnificaţie: T1 T2 reprezintă coordonatele nodului unde se află ţinta, S1 S2 coordonatele nodului în care este amplasată prima sursă, S3 S4 coordonatele nodului în care este amplasată a doua sursă, R1 R2 coordonatele poziţiei iniţiale a primului robot, respectiv R3 R4 coordonatele poziţiei iniţiale a celui de-al doilea robot;
  • pe a treia linie o valoare naturală k, reprezentând numărul obstacolelor din reţea;
  • pe următoarele k linii se găseşte câte o pereche de valori naturale separate printr-un spaţiu. Fiecare pereche reprezintă coordonatele unui nod în care este amplasat un obstacol.

Date de ieșire

Fișierul de ieșire ai.out va conține pe prima linie un număr natural ce reprezintă răspunsul la cerinţa 1) iar pe a doua linie un număr natural care reprezintă răspunsul la cerinţa 2).

Restricții și precizări

  • n ≤ 1000
  • k ≤ 150000
  • la începutul experimentului poziţiile ţintei, surselor laser, roboţilor şi obstacolelor sunt diferite.
  • roboţii nu pot ocupa şi nu pot trece prin nodul în care se află ţinta,
  • roboţii pot ocupa un nod în acelaşi timp.
  • un robot nu poate proteja ţinta faţă de o rază decât atunci când este plasat exact într-un nod, nu şi atunci când se află între două noduri.
  • un obstacol poate să aparţină în acelaşi timp atât unui zid orizontal cât şi unui zid vertical.
  • dacă fişierul de ieşire conţine o singură valoare, se consideră că aceasta reprezintă răspunsul la prima cerinţă
  • în toate testele efectuate, există cel puţin o posibilitate ca ţinta să fie apărată de către una dintre raze de unul dintre roboţi iar faţă de cealaltă rază să fie apărată de celălalt robot.
  • pentru rezolvarea primei cerinţe se acordă 20% din punctaj; pentru rezolvarea celei de-a doua cerinţe se acordă 80% din punctaj.

Exemplu

ai.in

6
4 4 1 1 6 5 1 3 3 4
8
1 2 
2 3 
2 5 
4 2 
6 2 
2 2 
2 4 
5 2

ai.out

4
8

Explicație

Cel mai lung zid are lungimea 4 (este cel plasat pe segmentul orizontal cu numărul 2); obstacolele de pe segmentul vertical 2 formează două ziduri cu lungimile 2 şi 3.

Primul robot ajunge în 4 secunde în poziţia 6 5 protejând astfel ţinta faţă de raza emisă de sursa din poziţia 6 5 iar al doilea în 8 secunde în poziţia 3 3 protejând astfel ţinta faţă de raza emisă de sursa din poziţia 1 1. După 8 secunde ţinta e protejată faţă de ambele raze laser.

Cum e corect?

cout < "As la info"; cout << "As la info"; cout >> "As la info";

Felicitări! Poți mai mult?

Avem sute de probleme pentru tine, fiecare cu explicații ușor de înțeles.

Greșit, dar nu-i bai!

Antrenează-te cu sutele de probleme pe care ți le-am pregătit. Îți explicăm fiecare problemă în parte.

Rezolvare

Iată rezolvarea de 100 de puncte pentru problema AI:

/*
    Stelian Ciurea
    lungimea maxima in k^2
    Complexitate: O(n*n)
*/

#include <iostream>
#include <fstream>
#include <queue>
#include <cstdlib>
#include <algorithm>
#define kmax 1000000
#define nmax 1000

using namespace std;

struct obstacol { int x,y;};
struct nod {
    int x,y,nrpasi;};

obstacol obs[kmax];

int a[nmax+2][nmax+2], opt[nmax+2][nmax+2];
nod poz1[nmax+2], poz2[nmax+2];
int n, xl1, xl2, yl1, yl2, xt, yt, xr1, xr2, yr1, yr2, x, y;
int i,j,k,t,nrpoz1,nrpoz2,lmax,lc,kt;
ifstream fin("ai.in");
ofstream fout("ai.out");
int min11, min12, min21, min22;
int depx[4]={0,1,0,-1};
int depy[4]={1,0,-1,0};

int compx(obstacol a, obstacol b)
{
    if (a.x > b.x)
        return 0;
    if (a.x == b.x && a.y > b.y)
        return 0;
    return 1;
}

int compy(obstacol a, obstacol b)
{
    if (a.y > b.y)
        return 0;
    if (a.y == b.y && a.x > b.x)
        return 0;
    return 1;
}

void Lee(int xst, int yst)
{
    queue <int> qx,qy;
    int xu, yu, i, xc, yc;
    qx.push(xst); qy.push(yst);
    opt[xst][yst] = 0;
    while (!qx.empty())
    {
        xc = qx.front(); yc=qy.front();
        qx.pop(); qy.pop();
        for (i=0;i<4;i++)
        {
            xu = xc + depx[i];
            yu = yc + depy[i];
            if (a[xu][yu] == 0)
                if (opt[xu][yu] > opt[xc][yc] + 1)
                {
                    opt[xu][yu] = opt[xc][yc] + 1;
                    qx.push(xu);
                    qy.push(yu);
                }
        }
    }
}

int ggt(int a, int b)
{
    while (a!=b)
        if (a>b) a-=b; else b-=a;
    return a;
}

void calcpoz(int xl1, int yl1, nod poz1[], int &nrpoz)
{
    int i,d,dx,dy,t=0;
    dx = xt - xl1; dy = yt - yl1;
    if (dx == 0)  //sunt in linie
            if (yt < yl1)
                for (i= yt+1; i<=yl1; i++)
                    poz1[t].x = xt, poz1[t].y=i, t++;
            else
                for (i= yl1; i<yt; i++)
                    poz1[t].x = xt, poz1[t].y=i, t++;
    else
        if (dy == 0)  //sunt in coloana
            if (xt < xl1)
                for (i= xt+1; i<=xl1; i++)
                    poz1[t].x = i, poz1[t].y=yt, t++;
            else
                for (i= xl1; i<xt; i++)
                    poz1[t].x = i, poz1[t].y=yt, t++;
        else
        {
            d = ggt(abs(dx),abs(dy));
            dx = abs(dx)/d, dy=abs(dy)/d;
            if (xl1 < xt && yl1 < yt)
                for (t=0,x=xl1,y=yl1;x+dx*t<xt;t++)
                    poz1[t].x=x+dx*t, poz1[t].y=y+dy*t;
            if (xl1 > xt && yl1 > yt)
                for (t=0,x=xl1,y=yl1;x-dx*t>xt;t++)
                    poz1[t].x=x-dx*t, poz1[t].y=y-dy*t;
            if (xl1 < xt && yl1 > yt)
                for (t=0,x=xl1,y=yl1;x+dx*t<xt;t++)
                    poz1[t].x=x+dx*t, poz1[t].y=y-dy*t;
            if (xl1 > xt && yl1 < yt)
                for (t=0,x=xl1,y=yl1;x-dx*t>xt;t++)
                    poz1[t].x=x-dx*t, poz1[t].y=y+dy*t;
        }
    nrpoz=t;
}

int main()
{
    fin >> n;
    fin >> xt >> yt >> xl1 >> yl1 >> xl2 >> yl2 >> xr1 >> yr1 >> xr2 >> yr2;
    fin >> k;
    for (i=1;i<=k;i++)
    {
        fin >> x >> y;
        obs[i].x=x; obs[i].y=y;
        a[x][y]=1;
        kt++;
    }
//  cout << kt << endl;
    lmax = 0;

    sort(obs+1,obs+k+1,compx);
    for (i=1;i<=k;i++)
    {
        //cout << obs[i].x<<" "<<obs[i].y<<"     ";
        if (obs[i].x == obs[i-1].x && obs[i].y == obs[i-1].y+1)
            lc++;
        else
            lc=0;
        if (lc > lmax)
            lmax = lc;
    }

    sort(obs+1,obs+k+1,compy);
    for (i=1;i<=k;i++)
    {
        //cout << obs[i].x<<" "<<obs[i].y<<"     ";
        if (obs[i].y == obs[i-1].y && obs[i].x == obs[i-1].x+1)
            lc++;
        else
            lc=0;
        if (lc > lmax)
            lmax = lc;
    }

    if (lmax>=1)
        fout << lmax+1 << '\n';
    else
        fout << "0\n";

    calcpoz(xl1,yl1,poz1,nrpoz1);
//  for (i=0;i<nrpoz1;i++)
//      cout << poz1[i].x<<" "<<poz1[i].y<<endl;
    calcpoz(xl2,yl2,poz2,nrpoz2);
//  for (i=0;i<nrpoz2;i++)
//      cout << poz2[i].x<<" "<<poz2[i].y<<endl;

    for (i=0;i<=n+1;i++)
        a[i][0] = a[0][i] = a[n+1][i] = a[i][n+1] = 1;
    for (i=1;i<=n;i++)
        for (j=1;j<=n;j++)
            opt[i][j] = n*n+1;

    a[xt][yt] = 1;
    Lee(xr1, yr1);
    min11 = min12 = n*n + 2;
    for (i=0;i<nrpoz1;i++)
    {
        x = poz1[i].x; y = poz1[i].y;
        if (min11 > opt[x][y])
            min11 = opt[x][y];
    }
    for (i=0;i<nrpoz2;i++)
    {
        x = poz2[i].x; y = poz2[i].y;
        if (min12 > opt[x][y])
            min12 = opt[x][y];
    }

    cout << min11<<" " << min12 << endl;
    /*
    for (i=1;i<=n;i++)
    {
        for (j=1;j<=n;j++)
        {
            cout.width(4);
            cout << opt[i][j];
        }
        cout << endl;
    }
    */

    Lee(xr2, yr2);
    min21 = min22 = n*n + 2;
    for (i=0;i<nrpoz1;i++)
    {
        x = poz1[i].x; y = poz1[i].y;
        if (min21 > opt[x][y])
            min21 = opt[x][y];
    }
    for (i=0;i<nrpoz2;i++)
    {
        x = poz2[i].x; y = poz2[i].y;
        if (min22 > opt[x][y])
            min22 = opt[x][y];
    }
    cout << min21<<" " << min22 << endl;
    /*
    for (i=1;i<=n;i++)
    {
        for (j=1;j<=n;j++)
        {
            cout.width(4);
            cout << opt[i][j];
        }
        cout << endl;
    }
    */
    if (max(min11,min22) < max(min12,min21))
        fout << max(min11, min22) << endl;
    else
        fout << max(min12, min21) << endl;
    fin.close();
    fout.close();
    return 0;
}

Atenție

Enunțurile afișate pe această pagină aparțin exclusiv site-ului PbInfo. Astfel, pentru ștergerea conținutului, puteți să ne contactați la adresa Adresa de email.

Rezolvarea problemei #1066 AI

Pe această pagină găsești rezolvarea de 100 de puncte pentru problema #1066 AI de pe PbInfo.ro. Atenție: nu încurajăm copiatul codului! Totuși, credem cu tărie că analizarea unei soluții corecte este o metodă foarte ușoară de a învăța informatică, astfel că oferim sursele pentru peste 1500 de probleme de pe platforma PbInfo.ro.

Pentru rezolvări PbInfo de la peste 1500 de probleme, vă invităm să intrați pe site-ul nostru!