Cod sursa(job #2802856)

Utilizator TonioAntonio Falcescu Tonio Data 18 noiembrie 2021 21:53:46
Problema Algoritmul lui Dijkstra Scor 20
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 12.2 kb
#include <fstream>
#include <vector>
#include <queue>
#include <stack>
#include <iostream>
#include <algorithm>
#include <limits.h>

using namespace std;

typedef pair<int, int> ii;

const int noduriMAX = 100001;

class Graf
{
private:
	int nrNoduri;
	int nrMuchii;
	int plecareBFS;
	vector <vector<int>> adiacenta;
	vector <vector<int>> ans; //pt muchie critica si pt biconexe
	vector <vector<ii>> adiacentaCosturi;

	void Tarjan(int nod, int nrPasi[], int minimPasi[],
		stack<int>* st, bool inSt[], vector<vector<int>>& afisare);
	void DFSTopologic(int start, bool vizitat[], stack <int>& st);
	void TBFA(int nod, int parinte, int nrPasi[], int minimPasi[]);
	void DFSBiconex(int nod, int nrPasi[], int minimPasi[], int parinte[], stack <pair<int, int>>& muchii);
	
public:
	void GrafNeorientat(string fisier);
	void GrafOrientat(string fisier);
	void DFS(int start, bool vizitat[]);
	void NumaraCompCnx();
	void CitireBFS();
	void BFS();
	void CTC();
	void HavelHakimi();
	void SortareTopologica();
	vector<vector<int>> criticalConnections(int n, vector<vector<int>>& connections);
	void Biconexe();
	void citireAPM(string fisier);
	void primAPM();
	void Djikstra();
};

void Graf::GrafNeorientat(string fisier)
{
	ifstream in(fisier);
	in >> nrNoduri >> nrMuchii;
	int start;
	int capat;
	adiacenta.resize(nrNoduri + 1);
	for (int i = 0; i < nrMuchii; ++i)
	{
		in >> start >> capat;
		adiacenta[start].push_back(capat);
		adiacenta[capat].push_back(start);
	}
	in.close();
}

void Graf::GrafOrientat(string fisier)
{
	ifstream in(fisier);
	in >> nrNoduri >> nrMuchii;
	int start;
	int capat;
	adiacenta.resize(nrNoduri + 1);
	for (int i = 0; i < nrMuchii; ++i)
	{
		in >> start >> capat;
		adiacenta[start].push_back(capat);
	}
	in.close();
}

void Graf::DFS(int start, bool vizitat[])
{
	vizitat[start] = true;
	for (int vecin : adiacenta[start])
	{
		if (!vizitat[vecin])
			DFS(vecin, vizitat);
	}
}

void Graf::NumaraCompCnx()
{
	ofstream out("dfs.out");
	int nrCompCnx = 0;
	bool vizitat[noduriMAX] = { false };
	for (int i = 1; i <= nrNoduri; ++i)
	{
		if (!vizitat[i])
		{
			DFS(i, vizitat);
			nrCompCnx++;
		}
	}
	out << nrCompCnx;
	out.close();
}

void Graf::CitireBFS()
{
	ifstream in("bfs.in");
	in >> nrNoduri >> nrMuchii >> plecareBFS;
	int start;
	int capat;
	adiacenta.resize(nrNoduri + 1);
	for (int i = 0; i < nrMuchii; ++i)
	{
		in >> start >> capat;
		adiacenta[start].push_back(capat);
	}
	in.close();
}

void Graf::BFS()
{
	queue <int> coadaBFS;
	int distanta[noduriMAX] = { 0 };
	ofstream out("bfs.out");
	int copiePlecareBFS = plecareBFS;
	bool vizitat[noduriMAX] = { false };
	vizitat[copiePlecareBFS] = true;
	coadaBFS.push(copiePlecareBFS);
	while (!coadaBFS.empty())
	{
		copiePlecareBFS = coadaBFS.front();
		coadaBFS.pop();
		for (int vecin : adiacenta[copiePlecareBFS])
			if (!vizitat[vecin])
			{
				vizitat[vecin] = true;
				distanta[vecin] = distanta[copiePlecareBFS] + 1;
				coadaBFS.push(vecin);
			}		
	}
	for (int i = 1; i <= nrNoduri; ++i)
	{
		if (!vizitat[i])
			out << -1 << " ";
		else
			out << distanta[i] << " ";
	}
		
	out.close();
}

void Graf::Tarjan(int nod, int nrPasi[], int minimPasi[], stack<int>* st, bool inSt[], vector<vector<int>>& afisare)
{
	//calc nr de pasi pt fiecare nod in DFS si pt fiecare nod dupa ce termin recursia pe vecinii sai 
	//actualizez minimul cu minimul dintre nod si cel mai jos copil al sau din arborele DFS
	static int pas = 0;
	nrPasi[nod] = minimPasi[nod] = ++pas;
	st->push(nod);
	inSt[nod] = true;

	for (int vecin : adiacenta[nod])
	{
		if (nrPasi[vecin] == -1)
		{
			Tarjan(vecin, nrPasi, minimPasi, st, inSt, afisare);
			minimPasi[nod] = min(minimPasi[nod], minimPasi[vecin]);
		}
		else if (inSt[vecin] == true)
			minimPasi[nod] = min(minimPasi[nod], nrPasi[vecin]);
	}
	if (minimPasi[nod] == nrPasi[nod])
	{
		vector <int> auxAfisare;
		while (st->top() != nod)
		{
			auxAfisare.push_back(st->top());
			inSt[st->top()] = false;
			st->pop();
		}
		auxAfisare.push_back(st->top());
		inSt[st->top()] = false;
		st->pop();
		afisare.push_back(auxAfisare);
	}
}

void Graf::CTC()
{
	int* nrPasi = new int[nrNoduri + 1];
	int* minimPasi = new int[nrNoduri + 1];
	bool* inSt = new bool[nrNoduri + 1];
	stack<int>* st = new stack<int>();
	vector < vector<int>> afisare;

	for (int i = 1; i <= nrNoduri; i++)
	{
		nrPasi[i] = -1;
		minimPasi[i] = -1;
		inSt[i] = false;
	}

	for (int i = 1; i <= nrNoduri; i++)
		if (nrPasi[i] == -1)
			Tarjan(i, nrPasi, minimPasi, st, inSt, afisare);

	ofstream out("ctc.out");
	out << afisare.size() << "\n";
	for (int i = 0; i < (int)afisare.size(); ++i)
	{
		for (int j = 0; j < (int)afisare[i].size(); ++j)
			out << afisare[i][j] << " ";
		out << "\n";
	}
	out.close();
}

void Graf::HavelHakimi()
{
	//facem urm:
	//sortam vect desc
	//scot primul elem (val v) si scad din celelalte v elem 1
	//pana cand:
	//toate elem sunt 0 (->exista)
	//v > vector.size() (->nu exista)
	//dupa ce scadem 1 din fiecare exista un elem care sa fie neg(->nu exista)
	ifstream in("havel.in");
	int x;
	bool ok = true;
	vector <int> v;
	while (in >> x)
		v.push_back(x);
	in.close();
	ofstream out("havel.out");
	while (true)
	{
		sort(v.begin(), v.end(), greater<>());
		if (v[0] == 0)
			break;

		int aux = v[0];
		v.erase(v.begin());
		if (aux > (int)v.size())
		{
			ok = false;
			break;
		}
		for (int i = 0; i < aux; ++i)
		{
			v[i]--;
			if (v[i] < 0)
			{
				ok = false;
				break;
			}
		}
		if (!ok)
			break;
	}
	ok ? out << "Da" : out << "Nu";
	out.close();
	
}

void Graf::DFSTopologic(int start, bool vizitat[], stack <int>& st)
{
	//dfs cu stiva in care punem elem curent
	//dupa ce am terminat recursia
	vizitat[start] = true;

	for (int vecin : adiacenta[start])
	{
		if (!vizitat[vecin])
			DFSTopologic(vecin, vizitat, st);
	}

	st.push(start);
}

void Graf::SortareTopologica()
{
	ofstream out("sortaret.out");
	stack <int> st;
	bool* vizitat = new bool[nrNoduri + 1];
	for (int i = 1; i <= nrNoduri; ++i)
		vizitat[i] = false;
	for (int i = 1; i <= nrNoduri; ++i)
		if (!vizitat[i])
			DFSTopologic(i, vizitat, st);
	
	while (!st.empty())
	{
		out << st.top() << " ";
		st.pop();
	}
	
	out.close();
}

void Graf::TBFA(int nod, int parinte, int nrPasi[], int minimPasi[])
{
	//la fel ca la CTC doar ca gasesc o muchie critica 
	//atunci cand un copil nu se poate duce mai sus in arborele de DFS decat nivelul tatalui
	static int pas = 0;
	nrPasi[nod] = minimPasi[nod] = ++pas;
	for (int vecin : adiacenta[nod])
	{
		if (nrPasi[vecin] == -1)
		{
			TBFA(vecin, nod, nrPasi, minimPasi);
			minimPasi[nod] = min(minimPasi[vecin], minimPasi[nod]);
		}
		else if (vecin != parinte)
			minimPasi[nod] = min(minimPasi[nod], nrPasi[vecin]);
		if (minimPasi[vecin] > nrPasi[nod])
			ans.push_back({ nod, vecin });
	}
}

vector<vector<int>> Graf::criticalConnections(int n, vector<vector<int>>& connections) {

	adiacenta.resize(n + 1);
	for (auto muchie : connections)
	{
		adiacenta[muchie[0]].push_back(muchie[1]);
		adiacenta[muchie[1]].push_back(muchie[0]);
	}
	int* nrPasi = new int[n];
	int* minimPasi = new int[n];
	for (int i = 0; i < n; i++)
	{
		nrPasi[i] = -1;
		minimPasi[i] = -1;
	}
	TBFA(0, -1, nrPasi, minimPasi);
	return ans;
}

void Graf::DFSBiconex(int nod, int nrPasi[], int minimPasi[], int parinte[], stack <pair<int, int>>& muchii)
{
	static int pas = 0;
	nrPasi[nod] = minimPasi[nod] = ++pas;
	int nrFii = 0;
	for (int vecin : adiacenta[nod])
	{
		if (nrPasi[vecin] == -1)
		{
			nrFii++;
			parinte[vecin] = nod;
			muchii.push({ nod, vecin });
			DFSBiconex(vecin, nrPasi, minimPasi, parinte, muchii);
			minimPasi[nod] = min(minimPasi[nod], minimPasi[vecin]);

			if ((parinte[nod] == -1 && nrFii > 1)	// pt rad
				|| (nrPasi[nod] != -1 && minimPasi[vecin] >= nrPasi[nod]))	//pt celelate noduri
			{
				vector <int> aux;
				while (muchii.top().first != nod && muchii.top().second != vecin)
				{
					aux.push_back(muchii.top().second);
					muchii.pop();
				}
				aux.push_back(muchii.top().second);
				aux.push_back(muchii.top().first);
				muchii.pop();
				ans.push_back(aux);
			}
		}
		else if (vecin != parinte[nod])
			minimPasi[nod] = min(minimPasi[nod], nrPasi[vecin]);
	}
}

void Graf::Biconexe()
{
	int* nrPasi = new int[nrNoduri + 1];
	int* minimPasi = new int[nrNoduri + 1];
	int* parinte = new int[nrNoduri + 1];
	stack<pair<int, int>> muchii;
	for (int i = 1; i <= nrNoduri; ++i)
	{
		nrPasi[i] = -1;
		minimPasi[i] = -1;
		parinte[i] = -1;
	}

	for (int i = 1; i <= nrNoduri; i++)
		if (nrPasi[i] == -1)
			DFSBiconex(i, nrPasi, minimPasi, parinte, muchii);

	ofstream out("biconex.out");
	out << ans.size() << "\n";
	for (auto comp : ans)
	{
		for (int nod : comp)
			out << nod << " ";
		out << "\n";
	}
	out.close();
}

void Graf::citireAPM(string fisier)
{
	ifstream in(fisier);
	in >> nrNoduri >> nrMuchii;
	int start;
	int capat;
	int cost;
	adiacentaCosturi.resize(nrNoduri + 1);
	for (int i = 0; i < nrMuchii; ++i)
	{
		in >> start >> capat >> cost;
		adiacentaCosturi[start].push_back(make_pair(capat, cost));
		adiacentaCosturi[capat].push_back(make_pair(start, cost));
	}
	in.close();
}

void Graf::primAPM()
{
	priority_queue<ii, vector<ii>, greater<ii>> noduriAPM;
	vector<int> costuri(nrNoduri + 1, 1001);
	vector<bool> inAPM(nrNoduri + 1, false);
	vector<int> parinte(nrNoduri + 1, -1);
	noduriAPM.push(make_pair(0, 1));
	costuri[1] = 0;
	
	while (!noduriAPM.empty())
	{
		int nod = noduriAPM.top().second;
		noduriAPM.pop();
		
		if (inAPM[nod])
			continue;

		inAPM[nod] = true;
		for (auto muchie : adiacentaCosturi[nod])
		{
			int vecin = muchie.first;
			int cost = muchie.second;
			if (costuri[nod] + cost < costuri[vecin])
			{
				costuri[vecin] = cost;
				noduriAPM.push(make_pair(cost, vecin));
				parinte[vecin] = nod;
			}
		}
	}
	ofstream out("apm.out");
	int s = 0;
	for (int i = 1; i <= nrNoduri; i++)
		s += costuri[i];
	out << s << "\n";
	out << nrNoduri - 1 << "\n";
	for (int i = 2; i <= nrNoduri; i++)
	{
		out << i << " " << parinte[i] << "\n";
	}
	
}

void Graf::Djikstra()
{
	ofstream out("dijkstra.out");

	priority_queue<ii, vector<ii>, greater<ii>> noduriDjik;
	vector<int> dist(nrNoduri + 1, INT_MAX);
	vector<bool> inDjik(nrNoduri + 1, false);
	noduriDjik.push(make_pair(0, 1));
	dist[1] = 0;
	while (!noduriDjik.empty())
	{
		int nod = noduriDjik.top().second;
		noduriDjik.pop();

		
		if (!inDjik[nod])
		{
			inDjik[nod] = true;
			for (auto muchie : adiacentaCosturi[nod])
			{
				int vecin = muchie.first;
				int cost = muchie.second;
				if (!inDjik[vecin] && dist[vecin] > dist[nod] + cost)
				{
					dist[vecin] = dist[nod] + cost;
					noduriDjik.push(make_pair(dist[vecin], vecin));
				}
			}
		}		
	}

	for (int i = 2; i <= nrNoduri; i++)
	{
		if (dist[i] != INT_MAX)
			out << dist[i] << " ";
		else
			out << 0 << " ";
			
	}
	out.close();
}

class Disjoint {
private:
	int nrElem;
	int nrOp;
	int* parinte;
	int* inaltime;

	int findRoot(int x)
	{
		if (parinte[x] != x)
			parinte[x] = findRoot(parinte[x]);

		return parinte[x];
	}

	void combin(int x, int y)
	{
		int xRoot = findRoot(x);
		int yRoot = findRoot(y);

		if (xRoot == yRoot)
			return;

		if (inaltime[xRoot] < inaltime[yRoot])
			parinte[xRoot] = yRoot;
		else if (inaltime[xRoot] > inaltime[yRoot])
			parinte[yRoot] = xRoot;
		else
		{
			parinte[yRoot] = xRoot;
			inaltime[xRoot] ++;
		}


	}
public:

	void afisare()
	{
		ifstream in("disjoint.in");
		ofstream out("disjoint.out");
		
		in >> nrElem >> nrOp;
		parinte = new int[nrElem + 1];
		inaltime = new int[nrElem + 1];
		for (int i = 1; i <= nrElem; i++)
			parinte[i] = i;
		int cod, x1, x2;
		for (int i = 0; i < nrOp; i++)
		{
			in >> cod >> x1 >> x2;
			if (cod == 1)
			{
				combin(x1, x2);
			}
			else
			{
				if (findRoot(x1) == findRoot(x2))
					out << "DA\n";
				else
					out << "NU\n";
					
			}
		}
		in.close();
		out.close();
	}
};

int main()
{
	Graf g;
	g.citireAPM("dijkstra.in");
	g.Djikstra();
	return 0;
}