Cod sursa(job #865692)

Utilizator evodaniVasile Daniel evodani Data 26 ianuarie 2013 20:50:59
Problema Ciclu Eulerian Scor 20
Compilator cpp Status done
Runda Arhiva educationala Marime 3.86 kb
//verific conexitatea si gradul fiecarui varf
//daca graful este eulerian, incep sa construiesc ciclul pornind
//de la un varf oarecare; atunci cand il inchid, il verific daca
//cuprinde fiecare muchie din graf; daca nu cuprinde, caut un varf
//de pe ciclu care sa aiba o muchie neprezenta in ciclu si pornind de la ea
//construiesc un nou ciclu; unesc cele doua cicluri si repet procesul.
//se poate aplica si pe multigraf, stergand din lista muchiilor pe cele
//incluse in ciclu (marcand 0)

#include <fstream>
#include <cstdlib>
using namespace std;
ifstream fin ("ciclueuler.in"); ofstream fout ("ciclueuler.out");
int *mat[101001], inc[101001], n, m, lg;
bool viz[101001];
struct nod {
    int vf, urm;
}ciclu[501001];
void dfs (short int s) {
    short int i;
    viz[s]=1;
    for (i=1; i<=mat[s][0]; ++i) if (!viz[mat[s][i]]) dfs(mat[s][i]);
}
void inserez (int unde, int vf, int urm) { ciclu[unde].vf=vf; ciclu[unde].urm=urm; }
int constr () {
    int lg=1, a, b, i=1;
    inserez(1, 1, 2); a=1;
    while (mat[a][i]!=1) {
        inserez(++lg, mat[a][i], lg+2);
        b=mat[a][i];
        mat[a][i]=0; --inc[a]; //sterg muchiile a-b, b-a
        for (i=1; i<=mat[b][0]; ++i) if (mat[b][i]==a) { mat[b][i]=0; break; } --inc[b];
        a=b; for (i=1; i<=mat[a][0]; ++i) if (mat[a][i]) break; //caut urmatoarea muchie
    } ciclu[lg].urm=0; //inchid ciclul\
    //sterg muchiile a-1, 1-a
    mat[a][i]=0; --inc[a];
    for (i=1; i<=mat[1][0]; ++i) if (mat[1][i]==a) { mat[1][i]=0; break; } --inc[1];
    //returnez numarul de muchii
    return lg;
}
void unesc (int s, int vf, int poz) {
    int a, b, i, aux=ciclu[poz].urm;
    ciclu[poz].urm=lg+1;
    inserez(++lg, mat[s][vf], lg+2);
    a=mat[s][vf];
    //sterg muchiile s-a, a-s
    mat[s][vf]=0; --inc[s];
    for (i=1; i<=mat[a][0]; ++i) if (mat[a][i]==s) { mat[a][i]=0; break; } --inc[a];
    for (i=1; i<=mat[a][0]; ++i) if (mat[a][i]) break; //caut urmatoarea muchie din a din afara
    while (mat[a][i]!=s) {
        inserez(++lg, mat[a][i], lg+2);
        b=mat[a][i];
        mat[a][i]=0; --inc[a]; //sterg muchiile a-b, b-a
        for (i=1; i<=mat[b][0]; ++i) if (mat[b][i]==a) { mat[b][i]=0; break; } --inc[b];
        a=b; for (i=1; i<=mat[a][0]; ++i) if (mat[a][i]) break;
    }
    inserez(++lg, s, lg+2); //inchid ciclul
    mat[a][i]=0; --inc[a]; //sterg muchiile a-s, s-a
    for (i=1; i<=mat[s][0]; ++i) if (mat[s][i]==a) { mat[s][i]=0; break; } --inc[s];
    ciclu[lg].urm=aux; //introduc ciclul in ciclu
}
int main()
{
    int i, a, b, j, poz; bool par=1;
    fin>>n>>m;
    for (i=1; i<=n; ++i) { mat[i]=(int*)realloc(mat[i], sizeof(int)); mat[i][0]=0; }
    for (i=1; i<=m; ++i) { //citesc multigraful
        fin>>a>>b;
        ++mat[a][0]; mat[a]=(int*)realloc(mat[a], sizeof(int)*(mat[a][0]+1)); mat[a][mat[a][0]]=b; ++inc[a];
        ++mat[b][0]; mat[b]=(int*)realloc(mat[b], sizeof(int)*(mat[b][0]+1)); mat[b][mat[b][0]]=a; ++inc[b];
    }
    for (i=1; i<=n && par; ++i) if (mat[i][0]%2==1) par=0; //verific gradul fiecarui varf
    if (par) { //verific conexitatea
        dfs(1);
        for (i=1; i<=n && par; ++i) if (!viz[i]) par=0;
    }
    if (par) { //graful este eulerian
        lg=constr();
        if (lg!=m) { i=1; while (!inc[ciclu[i].vf] && i<=lg) ++i; }
        while (i<=lg && lg!=m) {//nu am determinat inca ciclul eulerian - i mai are muchii incidente in afara
            for (j=1; j<=mat[ciclu[i].vf][0]; ++j) if (mat[ciclu[i].vf][j]) break; //caut prima muchie din afara
            unesc(ciclu[i].vf, j, i);
            if (lg!=m) { i=1; while (!inc[ciclu[i].vf] && i<=lg) ++i; }
        }
        fout<<1<<' '; poz=ciclu[1].urm;
        while (poz) {
            fout<<ciclu[poz].vf<<' ';
            poz=ciclu[poz].urm;
        }
        fout<<'\n';
    }
    else fout<<-1<<'\n'; //graful nu este eulerian
    fout.close();
    return 0;
}