#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <utility>
using namespace std;
class vertice;
class graph;
class edge {
vertice* start;
vertice* end;
int weight;
int capacity;
public:
edge(vertice* v1, vertice* v2) : start(v1), end(v2) {}
edge(vertice* v1, vertice* v2, int w) : start(v1), end(v2), weight(w) {}
edge(vertice* v1, vertice* v2, int w, int c) : start(v1), end(v2), weight(w), capacity(c) {}
void set_capacity(int cap) {capacity = cap;}
void set_weight(int wgt) {weight = wgt;}
int get_capacity() {return capacity;}
int get_weight() {return weight;}
friend ostream& operator<<(ostream& out, const graph& g);
friend class graph;
friend class oriented_graph;
friend class vertice;
};
class vertice {
protected:
int id;
vector<edge*> edges;
public:
vertice(int id) : id(id){}
void add_edge(edge* e) {edges.push_back(e);}
int get_id() {return id;}
friend ostream& operator<<(ostream& out, const graph& g);
friend class graph;
friend class oriented_graph;
friend class edge;
};
class oriented_vertice : public vertice{
vector<edge*> in_edges;
public:
oriented_vertice(int id) : vertice(id) {}
void add_in_edge(edge* e) {in_edges.push_back(e);}
friend class graph;
friend class oriented_graph;
friend class edge;
};
class graph {
protected:
int nr_vertices;
int nr_edges;
vector<vertice*> vertices;
vector<edge*> edges;
public:
graph() {vertices.push_back(new vertice(0));}
graph(int nr_vertices, int nr_edges) : nr_vertices(nr_vertices), nr_edges(nr_edges) {vertices.push_back(new vertice(0));}
virtual void add_vertice(vertice* v) {
vertices.push_back(v);
nr_vertices++;
}
virtual void add_edge(vertice* v1, vertice* v2) {
edge* e = new edge(v1, v2);
v1->add_edge(e);
v2->add_edge(e);
edges.push_back(e);
nr_edges++;
}
virtual bool edge_exists(int start, int end);
virtual void DFS(int start, vector<int>& visited);
virtual void DFS_start(int start);
virtual void BFS(int start);
friend istream& operator>>(istream& in, graph& g);
friend ostream& operator<<(ostream& out, const graph& g);
friend class vertice;
friend class edge;
};
class oriented_graph : public graph {
vector<oriented_vertice*> vertices;
public:
oriented_graph() : graph() {vertices.push_back(new oriented_vertice(0));}
oriented_graph(int nr_vertices, int nr_edges) : graph(nr_vertices, nr_edges) {vertices.push_back(new oriented_vertice(0));}
void add_vertice(oriented_vertice* v) {
vertices.push_back(v);
nr_vertices++;
}
void add_edge(oriented_vertice* v1, oriented_vertice* v2) {
edge* e = new edge(v1, v2);
v1->add_edge(e);
v2->add_in_edge(e);
edges.push_back(e);
nr_edges++;
}
bool edge_exists(int start, int end);
void DFS(int start, vector<int>& visited);
void DFS_start(int start);
void BFS(int start);
bool topo_sort();
friend istream& operator>>(istream& in, oriented_graph& og);
};
bool graph :: edge_exists(int start, int end) {
for (int i = 0; i < vertices[start]->edges.size(); i++) {
if ((vertices[start]->edges[i]->end->get_id() == end) || (vertices[start]->edges[i]->start->get_id() == end)){
return true;
}
}
return false;
}
bool oriented_graph :: edge_exists(int start, int end) {
for (int i = 0; i < vertices[start]->edges.size(); i++) {
if (vertices[start]->edges[i]->end->get_id() == end) {
return true;
}
}
return false;
}
void graph :: DFS(int start, vector<int>& visited) {
visited[start] = 1;
cout << start << " ";
for (int i = 0; i < vertices[start]->edges.size(); i++){
if (visited[vertices[start]->edges[i]->start->get_id()] == 0) {
DFS(vertices[start]->edges[i]->start->get_id(), visited);
}
else {
if (visited[vertices[start]->edges[i]->end->get_id()] == 0) {
DFS(vertices[start]->edges[i]->end->get_id(), visited);
}
}
}
}
void oriented_graph :: DFS(int start, vector<int>& visited) {
visited[start] = 1;
cout << start << " ";
for (int i = 0; i < vertices[start]->edges.size(); i++){
if (visited[vertices[start]->edges[i]->end->get_id()] == 0) {
DFS(vertices[start]->edges[i]->end->get_id(), visited);
}
}
}
void graph :: DFS_start(int start) {
vector<int> visited;
visited.resize(nr_vertices + 1);
for (int i = 1; i <= nr_vertices; i++) {
visited[i] = 0;
}
visited[start] = 1;
DFS(start, visited);
}
void oriented_graph :: DFS_start(int start) {
vector<int> visited;
visited.resize(nr_vertices + 1);
for (int i = 1; i <= nr_vertices; i++) {
visited[i] = 0;
}
visited[start] = 1;
DFS(start, visited);
}
void graph::BFS(int start) {
queue<int> vqueue;
vector<int> visited;
visited.resize(nr_vertices + 1);
for (int i = 1; i <= nr_vertices; i++) {
visited[i] = 0;
}
visited[start] = 1;
vqueue.push(start);
while (!vqueue.empty()) {
int curr = vqueue.front();
cout << curr << " ";
for (int i = 0; i < vertices[curr]->edges.size();i++) {
if (visited[vertices[curr]->edges[i]->start->get_id()] == 0) {
vqueue.push(vertices[curr]->edges[i]->start->get_id());
visited[vertices[curr]->edges[i]->start->get_id()] = 1;
}
else {
if (visited[vertices[curr]->edges[i]->end->get_id()] == 0) {
vqueue.push(vertices[curr]->edges[i]->end->get_id());
visited[vertices[curr]->edges[i]->end->get_id()] = 1;
}
}
}
vqueue.pop();
}
}
void oriented_graph::BFS(int start) {
queue<int> vqueue;
vector<int> visited;
visited.resize(nr_vertices + 1);
for (int i = 1; i <= nr_vertices; i++) {
visited[i] = 0;
}
visited[start] = 1;
vqueue.push(start);
while (!vqueue.empty()) {
int curr = vqueue.front();
cout << curr << " ";
for (int i = 0; i < vertices[curr]->edges.size();i++) {
if (visited[vertices[curr]->edges[i]->end->get_id()] == 0) {
vqueue.push(vertices[curr]->edges[i]->end->get_id());
visited[vertices[curr]->edges[i]->end->get_id()] = 1;
}
}
vqueue.pop();
}
}
bool oriented_graph :: topo_sort() {
vector<int> unused_vertices;
unused_vertices.resize(nr_vertices + 1);
vector<oriented_vertice*> sorted_vertices;
queue<oriented_vertice*> vqueue;
for (int i = 1; i <= nr_vertices; i++) {
unused_vertices[i] = vertices[i]->in_edges.size();
if (unused_vertices[i] == 0) {
vqueue.push(vertices[i]);
unused_vertices[i] = -1;
}
}
while (!vqueue.empty()) {
oriented_vertice* curr = vqueue.front();
sorted_vertices.push_back(curr);
for (int i = 0; i < curr->edges.size(); i++) {
unused_vertices[curr->edges[i]->end->get_id()]--;
}
for (int i = 1; i <= nr_vertices; i++) {
if (unused_vertices[i] == 0) {
vqueue.push(vertices[i]);
unused_vertices[i] = -1;
}
}
vqueue.pop();
}
if (sorted_vertices.size() != nr_vertices) {
return false;
}
ofstream fout("sortaret.out");
for (int i = 0; i < sorted_vertices.size(); i++) {
fout << sorted_vertices[i]->get_id() << " ";
}
return 1;
}
istream& operator>>(istream& in, graph& g) {
int nr_edges, nr_vertices, start, end;
in >> nr_vertices >> nr_edges;
g = *(new graph(0,0));
for (int i = 1; i <= nr_vertices; i++) {
vertice* v = new vertice(i);
g.add_vertice(v);
}
for (int i = 0; i < nr_edges; i++) {
in >> start >> end;
g.add_edge(g.vertices[start], g.vertices[end]);
}
return in;
}
istream& operator>>(istream& in, oriented_graph& og) {
int nr_edges, nr_vertices, start, end;
in >> nr_vertices >> nr_edges;
og = *(new oriented_graph(0,0));
for (int i = 1; i <= nr_vertices; i++) {
oriented_vertice* v = new oriented_vertice(i);
og.add_vertice(v);
}
for (int i = 0; i < nr_edges; i++) {
in >> start >> end;
og.add_edge(og.vertices[start], og.vertices[end]);
}
return in;
}
ostream& operator<<(ostream& out, const graph& g) {
out << g.nr_edges << " " << g.nr_vertices << endl;
for (int i = 0; i < g.nr_edges; i++) {
out << g.edges[i]->start->get_id() << " " << g.edges[i]->end->get_id() << endl;
}
return out;
}
int main() {
ifstream fin("sortaret.in");
oriented_graph g;
fin >> g;
g.topo_sort();
return 0;
}