#define NDEBUG #include #include #include using namespace std; const int MAXN = 100000; // N: numero di nodi. // M: numero di archi. int N, M; // Il grafo iniziale. // Archi già usati M->S, archi "diversi" S->M. // Nota: Mi == i, Si == N+i. // Posso invalidare gli archi con il valore -1. vector grafo[2*MAXN]; // Nodi scoperti ma non ancora visitati del tutto dalla DFS. bool scoperti[2*MAXN]; // Nodi visitati dalla DFS. bool visitati[2*MAXN]; // Numero di nodi visitati. int nvisitati; // padri[i]: il padre del nodo i, colui che l'ha scoperto. // NOTA: i valori sono significativi solo se i nodi in questione sono marcati // visitati o scoperti. int padri[2*MAXN]; void init_grafo(); // Ritorna true se ha trovato un ciclo e in tal caso l'arco (pivot,testa) chiude il ciclo. bool dfs_visita(int start, int &pivot, int &testa); // Opera sul grafo e ritorna l'indice nella lista di adiacenza di a che // corrisponde all'arco (a,b), -1 se l'arco non esite. int cercaArco(int a, int b); void aggiorna_archi(int pivot, int testa); void stampa_risultato(ofstream &ofs); #ifndef NDEBUG void stampa_grafo(ofstream &ofs, int m); #endif int main() { init_grafo(); #ifndef NDEBUG ofstream outdb("debugGrafo.txt"); stampa_grafo(outdb, 2*N); outdb.close(); #endif // Suppongo di non aver trovato cicli. bool ciclo = false; // L'arco (pivot,testa) chiude l'eventuale ciclo. int pivot, testa; // Inizializzazione. for ( int i = 0; i < N; ++i ) { scoperti[i] = false; visitati[i] = false; } nvisitati = 0; // Finché non ho visitato tutto il grafo (o trovato un ciclo). while( nvisitati < 2*N) { int start = 0; // Cerco un nodo non ancora visitato. for (int i = 0; i < 2*N; ++i) if ( !visitati[i] ) { start = i; break; } padri[start] = -1; // DFS sul grafo per trovare eventuali cicli. ciclo = dfs_visita(start, pivot, testa); // Ho trovato un ciclo. if ( ciclo ) break; } // Stampa il risultato. ofstream out("output.txt"); if (ciclo) { // Ho trovato un ciclo, quindi aggiorno gli archi in modo da avere la nuova assegnazione. aggiorna_archi(pivot,testa); #ifndef NDEBUG ofstream outdb("debugGrafoNuovo.txt"); stampa_grafo(outdb, 2*N); outdb.close(); #endif stampa_risultato(out); } else out << -1 << endl; out.close(); } //+ void init_grafo() { ifstream in("input.txt"); assert(in); in >> N >> M; assert( 1 <= N && N <= MAXN ); int a, b; for ( int i = 0; i < N; ++i ) { in >> a >> b; // Archi già usati. grafo[a].push_back(b+N); } for ( int i = N; i < M; ++i ) { in >> a >> b; // Archi nuovi. grafo[b+N].push_back(a); } in.close(); } //+ // Visita il grafo con gli assegnamenti a partire da start e cerca i cicli. bool dfs_visita(int start, int &pivot, int &testa) { assert( 0 <= start && start <= 2*N-1 ); scoperti[start] = true; // Visito tutti i figli e se trovo un arco all'indietro ritorno true. for ( unsigned int i = 0; i < grafo[start].size(); ++i ) { // Nota: visitato => scoperto. // Nuovo nodo, non ancora scoperto. if ( !scoperti[grafo[start][i]] ) { // Setto il padre per ricosturire il ciclo (se c'è). padri[grafo[start][i]] = start; scoperti[grafo[start][i]] = true; if ( dfs_visita(grafo[start][i], pivot, testa) ) return true; } // Nodo scoperto ma non visitato => ciclo. else if ( !visitati[grafo[start][i]] && scoperti[grafo[start][i]] ) { pivot = start; testa = grafo[start][i]; return true; } // Nodo visitato non devo fare nulla. } // Ho visitato tutti i figli senza trovare cicli, quindi mi marco come visitato e ritorno false. visitati[start] = true; ++nvisitati; return false; } //+ int cercaArco(int a, int b) { for ( unsigned int i = 0; i < grafo[a].size(); ++i ) if ( grafo[a][i] == b ) return static_cast(i); return -1; } //+ void aggiorna_archi(int pivot, int testa) { // Parto dal pivoqt. int inizio = pivot; int coda = testa; // Finché non ho raggiunto la testa, ciclo. while ( true ) { // Inverto tutti gli archi lungo il ciclo. int idx = cercaArco(inizio, coda); assert(idx != -1); // Invalido il vecchio arco. grafo[inizio][idx] = -1; grafo[coda].push_back(inizio); // Mi sposto. coda = inizio; inizio = padri[inizio]; // Mi fermo. if ( coda == testa ) break; } } //+ void stampa_risultato(ofstream &ofs) { for ( int i = 0; i < N; ++i ) for ( unsigned int j = 0; j < grafo[i].size(); ++j ) if (grafo[i][j] != -1) ofs << i << " " << grafo[i][j]-N << endl; } //+ #ifndef NDEBUG void stampa_grafo(ofstream &ofs, int m) { for ( int i = 0; i < m; ++i ) for ( unsigned int j = 0; j < grafo[i].size(); ++j ) if (grafo[i][j] != -1) ofs << i << " " << grafo[i][j] << endl; } #endif