Cod sursa(job #2797217)

Utilizator AlexCrpCarpineanu Alexandru AlexCrp Data 9 noiembrie 2021 16:16:28
Problema Sortare topologica Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 12.18 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <stack>
#include <algorithm>

using namespace std;

ifstream fin("sortaret.in");
ofstream fout("sortaret.out");

class Graf
{
private:

	int nrMuchii, nrNoduri;
	vector<vector<int>> listaAdiacenta;
	bool orientat;

	void adaugaMuchie(int, int, bool);		    //Am decis sa fac adaugarea unei muchii in lista de adiacenta o functie, poate o sa fie useful later?
	void DFSAux(int, vector<bool>&);			//Functie auxiliara pt problema DFS de pe infoarena
	void BCXAux(int, int&, vector<int>&, vector<int>&, vector<int>&, stack<int>&, vector<vector<int>>&);		//Metoda auxiliara pt problema Componente Biconexe de pe infoarena
	void CTCAux(int, int&, vector<int>&, vector<int>&, vector<bool>&, stack<int>&, vector<vector<int>>&);
	void MuchiiAux(int, int&, vector<int>&, vector<int>&, vector<int>&, vector<bool>&, vector<vector<int>>&);
	void DFSTopological(int, vector<bool>&, stack<int>&);			//Metoda care returneaza arborele DFS al grafului (maybe useful later)
public:
	Graf();
	Graf(int, int, bool);
	void BFS(int);							//Functie care rezolva problema BFS de pe infoarena
	int DFSrezolvare(int);					//Functie care rezolva problema DFS de pe infoarena
	void Biconexe();						//Functie care rezolva problema Componente Biconexe de pe infoarena
	void HavelHakimi();
	void CTC();
	void MuchiiCrit();
	void SortareTopologica();
};

Graf::Graf()
{
	nrMuchii = 0;
	nrNoduri = 0;
	orientat = false;
}

Graf::Graf(int n, int m, bool orr)
{
	int x, y;

	nrNoduri = n;
	nrMuchii = m;
	orientat = orr;
	listaAdiacenta.resize(nrNoduri + 1);	//Construim si reprezentarea grafului in constructor

	for (int i = 0; i < nrMuchii; i++)
	{
		fin >> x >> y;
		adaugaMuchie(x, y, orientat);
	}
}

void Graf::adaugaMuchie(int n1, int n2, bool orr)
{
	listaAdiacenta[n1].push_back(n2);
	if (!orr)
	{
		listaAdiacenta[n2].push_back(n1);
	}
}

void Graf::BFS(int nodStart)
{
	queue<int> q;
	vector<bool> vizitate(nrNoduri+1, false);		//vector de bool initializat cu false, in el vom retine daca nodurile au fost vizitate
	vector<int> distante(nrNoduri+1, -1);			//vector de int care retine distantele de la nodul de start, initializat cu -1

	q.push(nodStart);

	vizitate[nodStart] = true;
	distante[nodStart] = 0;

	while (!q.empty())
	{
		int nodCurent = q.front();
		q.pop();

		for (int nodVecin : listaAdiacenta[nodCurent])
		{
			if (!vizitate[nodVecin])
			{
				vizitate[nodVecin] = true;			//BFS normal, iar in if() calculam si distanta dintre nodul curent si nodul de start
				q.push(nodVecin);					//Distanta creste cu 1 de fiecare data cand trecem de la un nod la altul
				distante[nodVecin] = distante[nodCurent] + 1;
			}
		}
	}

	for (int i=1; i < distante.size(); i++)
	{
		fout << distante[i] << ' ';					//Afisam distantele
	}
}

void Graf::DFSAux(int nodStart, vector<bool>& vizitate)
{
	vizitate[nodStart] = true;
	for (int i : listaAdiacenta[nodStart])
	{
		if (!vizitate[i])					//DFS care modifica lista de noduri vizitate din metoda care rezolva problema DFS
		{
			DFSAux(i, vizitate);
		}
	}
	
}

int Graf::DFSrezolvare(int nodStart)
{
	vector<bool> vizitate(nrNoduri+1, false);
	int nrComponente = 0;
	
	for (int i = 1; i < vizitate.size(); i++)
	{
		if (!vizitate[i])
		{									//Incrementam numarul de componente pentru fiecare apel al DFSAux
			DFSAux(i, vizitate);			//Pt ca fiecare apel DFS marcheaza toate nodurile din cate o componenta conexa
			nrComponente++;					//Deci fiecare apel ne baga intr-o componenta conexa noua
		}
	}
	return nrComponente;
}

void Graf::DFSTopological(int nodStart, vector<bool>& vizitate, stack<int>& s)
{
	vizitate[nodStart] = true;
	for (int i : listaAdiacenta[nodStart])
	{
		if (!vizitate[i])
		{
			DFSTopological(i, vizitate, s);
		}
	}
	s.push(nodStart);
}

void Graf::BCXAux(int nodStart, int& adancimeStart, vector<int>& adancimi, vector<int>& adancimeMinima, vector<int>& parinti, stack<int>& s, vector<vector<int>>& componenteBCX)
{
	adancimi[nodStart] = adancimeStart;					//vector care retine adancimea nodurilor in parcurgerea DFS
	adancimeMinima[nodStart] = adancimeStart;			//vector care retine cat de sus(adancime) poate un nod sa ajunga pe un drum in "jos"
	adancimeStart++;									//adancimea curenta in DFS

	for (auto vecin : listaAdiacenta[nodStart])
	{
		s.push(nodStart);								//pusham fiecare nod in stiva
		
		if (parinti[vecin] == -1)						//=> vecin nu este vizitat
		{
			parinti[vecin] = nodStart;					//parintele vecinului va fi nodul cuc are apelam functia

			BCXAux(vecin, adancimeStart, adancimi, adancimeMinima, parinti, s, componenteBCX);		//DFS

			adancimeMinima[nodStart] = min(adancimeMinima[vecin], adancimeMinima[nodStart]);		//actualizam adancimea minima a nodului curent
																									//practic verificam daca fiul sau poate ajunge la un stramos al lui
																																											
				
			if (adancimi[nodStart] <= adancimeMinima[vecin])			//nodStart == punct critic    =>    aici se termina componenta biconexa
			{
				vector<int> componenta;
				componenta.push_back(nodStart);

				vector<bool> adaugat(nrNoduri + 1, false);				//nevoie de acest vector pt ca pusham acelasi nod de mai multe ori in stiva in unele cazuri
				adaugat[nodStart] = true;								

				int nod = s.top();
				s.pop();
				componenta.push_back(nod);
				adaugat[nod] = true;

				while (nod != nodStart)						//construim componenta cu toate nodurile din stiva 
				{												
					nod = s.top();					
					s.pop();
					if (!adaugat[nod]) {
						componenta.push_back(nod);
						adaugat[nod] = true;
					}	
				}

				componenteBCX.push_back(componenta);
			}
		}
		else
		{
			adancimeMinima[nodStart] = min(adancimi[vecin], adancimeMinima[nodStart]);				//daca vecin este vizitat => adancimi[vecin] < adancimi[nodStart]
		}																							//=> actualizam adancimeaMinima[nodStart] cu minimul dintre adancimea 
																									//vecinului si adancimeaMinima a nodStart
		
	}
}

void Graf::Biconexe()
{
	vector<int> adancimi(nrNoduri + 1, -1);
	vector<int> adancimeMinima(nrNoduri + 1, -1);
	stack<int> s;
	vector<vector<int>> componente;
	vector<int> parinti(nrNoduri + 1, -1);
	int adancime = 1;
	parinti[1] = 1;
	BCXAux(1,adancime,adancimi,adancimeMinima,parinti,s, componente);

	fout << componente.size() << "\n";
	for (auto i : componente)
	{
		for (auto j : i)
		{
			fout << j << ' ';
		}
		fout << "\n";
	}

	
}

void Graf::HavelHakimi()
{
	int n, nod;
	vector<int> secventa;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> nod;
		secventa.push_back(nod);
	}
	while (true) {
		sort(secventa.begin(), secventa.end());
		int deScazut = secventa[0];

		secventa.erase(secventa.begin());
		
		if (secventa.size() < deScazut)
		{
			cout << "Nu merge";
			break;
		}

		for (int i = 0; i < deScazut; i++)
		{
			secventa[i]--;
		}

		bool merge = true;
		bool nuMerge = false;

		for (int i = 0; i < secventa.size(); i++)
		{
			if (secventa[i] != 0)
			{
				merge = false;
			}

			if (secventa[i] < 0)
			{
				nuMerge = true;
				break;
			}
		}

		if (merge)
		{
			cout << "merge";
			break;
		}

		if (nuMerge)
		{
			cout << "nu merge";
			break;
		}
	}
	
}

void Graf::CTCAux(int nodStart, int& adancimeStart, vector<int>& adancimi, vector<int>& adancimeMinima, vector<bool>& peStiva, stack<int>& s, vector<vector<int>>& componenteCTC)
{
	adancimi[nodStart] = adancimeStart;					//vector care retine adancimea nodurilor in parcurgerea DFS
	adancimeMinima[nodStart] = adancimeStart;			//vector care retine cat de sus(adancime) poate un nod sa ajunga pe un drum in "jos"
	adancimeStart++;									//adancimea curenta in DFS

	s.push(nodStart);								//pusham fiecare nod in stiva

	peStiva[nodStart] = true;

	for (auto vecin : listaAdiacenta[nodStart])
	{
		if (adancimi[vecin] == -1)						//=> vecin nu este vizitat
		{
			CTCAux(vecin, adancimeStart, adancimi, adancimeMinima, peStiva, s, componenteCTC);		//DFS

			adancimeMinima[nodStart] = min(adancimeMinima[vecin], adancimeMinima[nodStart]);		//actualizam adancimea minima a nodului curent
																									//practic verificam daca fiul sau poate ajunge la un stramos al lui
		}
		else if(peStiva[vecin] == true)
		{
			adancimeMinima[nodStart] = min(adancimi[vecin], adancimeMinima[nodStart]);				//daca vecin este vizitat => adancimi[vecin] < adancimi[nodStart]
		}																							//=> actualizam adancimeaMinima[nodStart] cu minimul dintre adancimea 
																									//vecinului si adancimeaMinima a nodStart
	}

	int nod;

	if (adancimeMinima[nodStart] == adancimi[nodStart])							//varful subarborelui care formeaza CTC
	{
		vector<int>componenta;
		while (s.top() != nodStart)
		{
			nod = s.top();
			componenta.push_back(nod);						//construim componenta si o pusham in vectorul de componente
			peStiva[nod] = false;
			s.pop();
		}
		nod = s.top();
		componenta.push_back(nod);
		componenteCTC.push_back(componenta);
		peStiva[nod] = false;
		s.pop();

	}
}

void Graf::CTC()
{
	vector<int> adancimi(nrNoduri + 1, -1);
	vector<int> adancimeMinima(nrNoduri + 1, -1);
	stack<int> s;
	vector<vector<int>> componente;
	vector<bool> peStiva(nrNoduri + 1, false);
	int adancime = 1;
	for (int i = 1; i < nrNoduri + 1; i++)
	{
		if (adancimi[i] == -1)
		{
			CTCAux(i, adancime, adancimi, adancimeMinima, peStiva, s, componente);
		}
	}
	fout << componente.size() << "\n";
	for (auto i : componente)
	{
		for (auto j : i)
		{
			fout << j << ' ';
		}
		fout << "\n";
	}
}

void Graf::MuchiiAux(int nodStart, int& adancimeStart, vector<int>& adancimi, vector<int>& adancimeMinima, vector<int>& parinti, vector<bool>& vizitate, vector<vector<int>>& MuchiiCritice)
{
	adancimi[nodStart] = adancimeStart;					//vector care retine adancimea nodurilor in parcurgerea DFS
	adancimeMinima[nodStart] = adancimeStart;			//vector care retine cat de sus(adancime) poate un nod sa ajunga pe un drum in "jos"
	adancimeStart++;									//adancimea curenta in DFS
	vizitate[nodStart] = true;
	for (auto vecin : listaAdiacenta[nodStart])
	{
		if (!vizitate[vecin])						//=> vecin nu este vizitat
		{

			parinti[vecin] = nodStart;					//parintele vecinului va fi nodul cuc are apelam functia

			MuchiiAux(vecin, adancimeStart, adancimi, adancimeMinima, parinti, vizitate, MuchiiCritice);		//DFS

			adancimeMinima[nodStart] = min(adancimeMinima[vecin], adancimeMinima[nodStart]);		//actualizam adancimea minima a nodului curent
																									//practic verificam daca fiul sau poate ajunge la un stramos al lui
			
			
			if (adancimeMinima[vecin] > adancimi[nodStart])				//conditie muchie critica
			{
				vector<int> muchieCritica;
				muchieCritica.push_back(nodStart);
				muchieCritica.push_back(vecin);

				MuchiiCritice.push_back(muchieCritica);
			}

		}
			
		else if(vecin != parinti[nodStart])				
		{
			adancimeMinima[nodStart] = min(adancimi[vecin], adancimeMinima[nodStart]);				//daca vecin este vizitat => adancimi[vecin] < adancimi[nodStart]
		}																							//=> actualizam adancimeaMinima[nodStart] cu minimul dintre adancimea 
																									//vecinului si adancimeaMinima a nodStart

	}
}

void Graf::MuchiiCrit()
{
	vector<bool> vizitate(nrNoduri + 1, false);
	vector<int> adancimi(nrNoduri + 1, -1);
	vector<int> adancimeMinima(nrNoduri + 1, -1);
	vector<vector<int>> muchii;
	vector<int> parinti(nrNoduri + 1, -1);
	int adancime = 1;
	parinti[1] = 1;
	for (int i = 1; i < vizitate.size(); i++) 
	{
		if (!vizitate[i])
		{
			MuchiiAux(i, adancime, adancimi, adancimeMinima, parinti,vizitate, muchii);
		}
	}
	for (auto i : muchii)
	{
		for (auto j : i)
		{
			fout << j << ' ';
		}
		fout << "\n";
	}


}

void Graf::SortareTopologica()
{
	stack<int> s;
	vector<bool> vizitate(nrNoduri + 1, false);

	for (int i = 1; i < vizitate.size(); i++)
	{
		if (!vizitate[i])
		{
			DFSTopological(i, vizitate, s);
		}
	}

	while (!s.empty())
	{
		fout << s.top()<<' ';
		s.pop();
	}
}

int main()
{
	int n, m;
	fin >> n >> m;
	Graf G(n, m, true);
	
	G.SortareTopologica();

	return 0;
}