Графы. Алгоритмы на графах

MTUCI ICPC

Graph be like:

Oriented graph be like

Хранение графов в памяти. Невзвешенный граф

int main() {
    int n_vertices,n_edges;
    cin>>n_vertices>>n_edges;
    vector<vector<int>> graph1(n_vertices,vector<int>(n_vertices));
    vector<vector<int>> graph2(n_vertices);
    vector<pair<int,int>> graph3;
    int a,b;
    for (int i=0;i<n_edges;++i){
        cin>>a>>b;
        graph1[a][b]=1;
        graph2[a].push_back(b);
        graph3.emplace_back(a,b);
    }
}
# PRESENTING CODE

Взвешенный случай

struct Edge{
    int a;
    int b;
    int w;
};

int main() {
    int n_vertices,n_edges;
    cin>>n_vertices>>n_edges;
    vector<vector<int>> graph1(n_vertices,vector<int>(n_vertices)); //матрица смежности
    vector<vector<pair<int,int>>> graph2(n_vertices); //списки смежности
    vector<Edge> graph3; //список ребер
    int a,b,w;
    for (int i=0;i<n_edges;++i){
        cin>>a>>b>>w;
        graph1[a][b]=w;
        graph2[a].emplace_back(b,w);
        graph3.push_back(Edge{a,b,w});
    }
}
# PRESENTING CODE

Поиск в глубину и его применения:

  • Поиск любого пути в графе.
  • Поиск лексикографически первого пути в графе.
  • Проверка, является ли одна вершина дерева предком другой
  • Задача LCA (наименьший общий предок).
  • Топологическая сортировка:
  • Проверка графа на ацикличность и нахождение цикла
  • Поиск компонент сильной связности
  • Поиск мостов

 

Поиск в глубину(DFS)

void DFS(const vector<vector<pair<int,int>>>& graph, vector<bool>& visited, int vertex){
    visited[vertex]=true;
    for (auto v:graph[vertex]){
        int new_vert=v.first;
        if(!visited[new_vert]){
        DFS(graph,visited,new_vert);}
    }
}
# PRESENTING CODE

Поиск компонент связностей

Решение задачи подсчета компонент связности

#include <iostream>
#include "algorithm"
#include "vector"

using namespace std;
void DFS(const vector<vector<pair<int,int>>>& graph, vector<bool>& visited, int vert){
    visited[vert]=true;
    for (auto a:graph[vert]){
        int node=a.first;
        if(!visited[node]){
            DFS(graph, visited, node);
        }
    }
}

int main() {
    int n_vertices,n_edges;
    cin>>n_vertices>>n_edges;
    vector<vector<pair<int,int>>> graph2(n_vertices); //списки смежности
    int a,b,w;
    for (int i=0;i<n_edges;++i){
        cin>>a>>b;
        graph2[a-1].emplace_back(b-1,1);
        graph2[b-1].emplace_back(a-1,1);
    }
    vector<bool> visited(n_vertices,false);
    int count=1;
    DFS(graph2, visited,0);
    for (int i=1;i<n_vertices;++i){
        if(!visited[i]){
            count++;
            DFS(graph2, visited, i);
        }
    }
    cout<<'\n'<<count;
}
# PRESENTING CODE

Проверка графа на двудольность

Код для проверки на двудольность

enum color {
    RED, BLUE, GRAY
};

color invert_colors(color a) {
    if (a == RED) {
        return BLUE;
    }
    return RED;
}

bool DFS(const vector<vector<int>> &graph, vector<color> &visited, int vert, color pred) {
    visited[vert] = pred;
    bool f=true;
    for (auto node: graph[vert]) {
        if (visited[node] == GRAY) {
            f&=DFS(graph, visited, node, invert_colors(visited[vert]));
        }
        else if (visited[node] == visited[vert]) {
            return false;
        }
    }
    return f;
}

int main() {
    int n_vertices, n_edges;
    cin >> n_vertices >> n_edges;
    vector<vector<pair<int, int>>> graph2(n_vertices); //списки смежности
    int a, b, w;
    for (int i = 0; i < n_edges; ++i) {
        cin >> a >> b;
        graph2[a - 1].emplace_back(b - 1, 1);
        graph2[b - 1].emplace_back(a - 1, 1);
    }
    vector<color> visited(n_vertices, GRAY);
    cout<<DFS(graph2,visited, 0, RED);
}
# PRESENTING CODE

Поиск мостов в графе:

void DFS(const vector<vector<pair<int, int>>> &graph, vector<bool> &visited, int vert, int pt, int pred, vector<int>& tin,vector<int>& tmin) {
    int cur_time=pt+1;
    tin[vert]=cur_time;
    tmin[vert]=cur_time;
    visited[vert] = true;
    for (auto a: graph[vert]) {
        int node = a.first;
        if(node==pred){
            continue;
        }
        if (!visited[node]) {
            DFS(graph, visited, node,cur_time,vert,tin,tmin);
            tmin[vert]=min(tmin[vert], tmin[node]);
            if(tmin[vert]<tmin[node]){
                cout<<vert+1<<' '<<node+1<<'\n';
            }
        }
        else{
            tmin[vert]=min(tmin[vert], tmin[node]);
        }
    }
}

int main() {
    int n_vertices, n_edges;
    cin >> n_vertices >> n_edges;

    vector<vector<pair<int, int>>> graph2(n_vertices); //списки смежности
    int a, b, w;
    for (int i = 0; i < n_edges; ++i) {
        cin >> a >> b;
        graph2[a - 1].emplace_back(b - 1, 1);
        graph2[b - 1].emplace_back(a - 1, 1);
    }
    vector<int> time_in(n_vertices,1e7);
    vector<int> time_min(n_vertices,1e7);

    vector<bool> visited(n_vertices, false);
    DFS(graph2,visited, 0, -1,-1,time_in,time_min);
}
# PRESENTING CODE

Код решения

Поиск цикла в графе

const int INF = 1e9;
using namespace std;
void DFS(const vector<vector<pair<int,int>>>& graph, vector<int>& visited,  int vertex, int time_pred){
    visited[vertex]=time_pred+1;
    for (auto v:graph[vertex]){
        int node =v.first;
        if(visited[node]<visited[vertex]){
            cout<<"Hello, I'm cycled";
            return;
        }
        if(visited[node]==INF){
        	DFS(graph, visited, node, visited[vertex]);
        }
    }
}
int main() {
    int n_vertices, n_edges;
    cin >> n_vertices >> n_edges;
    vector<vector<pair<int, int>>> graph2(n_vertices); //списки смежности
    int a, b, w;
    for (int i = 0; i < n_edges; ++i) {
        cin >> a >> b;
        graph2[a - 1].emplace_back(b - 1, 1);
    }
    vector<int> visited(n_vertices, INF);
    DFS(graph2, visited, 0, -1);
}
# PRESENTING CODE

Решение для поиска цикла

Топологическая сортировка графа

# PRESENTING CODE
const int INF = 1e9;
using namespace std;
void DFS(const vector<vector<pair<int,int>>>& graph, vector<bool>& visited,  int vertex, vector<int>& ans){
    visited[vertex]=true;
    for (auto v:graph[vertex]){
        int node =v.first;
        if(!visited[node]){
            DFS(graph, visited, node, ans);
        }
    }
    ans.push_back(vertex);
}
int main() {
    int n_vertices, n_edges;
    cin >> n_vertices >> n_edges;
    vector<vector<pair<int, int>>> graph2(n_vertices); //списки смежности
    int a, b, w;
    for (int i = 0; i < n_edges; ++i) {
        cin >> a >> b;
        graph2[a - 1].emplace_back(b - 1, 1);
    }
    vector<bool> visited(n_vertices, false);
    vector<int> ans;
    DFS(graph2, visited, 0,ans);
    for (auto i=ans.rbegin();i<ans.rend();i++){
        cout<<*i<<'\n';
    }
}
# PRESENTING CODE

Решение

Поиск компонент сильной связности

#include "iostream"
#include "vector"

void TopSort(const std::vector<std::vector<int>>& graph, std::vector<bool>& visited, int vertex, std::vector<int>& order){
    visited[vertex]=true;
    for (int node: graph[vertex]){
        if(!visited[node]){
            TopSort(graph,visited, node, order);
        }
    }
    order.push_back(vertex);
}

void DFS(const std::vector<std::vector<int>>& graph, std::vector<bool>& visited, int vertex, std::vector<int>& component, int n_comp){
    component[vertex]=n_comp;
    for (int node: graph[vertex]){
        if(component[node]==0){
            DFS(graph, visited, node, component, n_comp);
        }
    }
}
int main(){
    size_t n_vertices, n_edges;
    std::cin>>n_vertices>>n_edges;
    std::vector<std::vector<int>> graphIshod(n_vertices, std::vector<int>());
    std::vector<std::vector<int>> graphT(n_vertices, std::vector<int>());
    int a,b;
    for(size_t i=0;i<n_edges;++i){
        std::cin>>a>>b;
        graphIshod[a - 1].push_back(b - 1);
        graphT[b-1].push_back(a-1);
    }
    std::vector<bool> visited(n_vertices);
    std::vector<int> order;
    for (int i=0;i<n_vertices;++i){
        if(!visited[i]){
            TopSort(graphIshod, visited, i, order);
        }
    }
    std::reverse(order.begin(), order.end());
    std::vector<int> component(n_vertices, 0);
    int n_comp=1;
    for (int i:order){
        if(component[i]==0){
            DFS(graphT,visited,i,component,n_comp);
            n_comp++;
        }
    }
    for(size_t i=0;i<n_vertices;++i){
        std::cout<<i<<' '<<component[i]<<'\n';
    }
    return 0;
}
# PRESENTING CODE

Конденсация графа

#include "iostream"
#include "vector"
#include "set"

void TopSort(const std::vector<std::vector<int>>& graph, std::vector<bool>& visited, int vertex, std::vector<int>& order){
    visited[vertex]=true;
    for (int node: graph[vertex]){
        if(!visited[node]){
            TopSort(graph,visited, node, order);
        }
    }
    order.push_back(vertex);
}

void DFS(const std::vector<std::vector<int>>& graph, std::vector<bool>& visited, int vertex, std::vector<int>& component, int n_comp){
    component[vertex]=n_comp;
    for (int node: graph[vertex]){
        if(component[node]==0){
            DFS(graph, visited, node, component, n_comp);
        }
    }
}
int main(){
    size_t n_vertices, n_edges;
    std::cin>>n_vertices>>n_edges;
    std::vector<std::vector<int>> graphIshod(n_vertices, std::vector<int>());
    std::vector<std::vector<int>> graphT(n_vertices, std::vector<int>());
    int a,b;
    for(size_t i=0;i<n_edges;++i){
        std::cin>>a>>b;
        graphIshod[a - 1].push_back(b - 1);
        graphT[b-1].push_back(a-1);
    }
    std::vector<bool> visited(n_vertices);
    std::vector<int> order;
    for (int i=0;i<n_vertices;++i){
        if(!visited[i]){
            TopSort(graphIshod, visited, i, order);
        }
    }
    std::reverse(order.begin(), order.end());
    std::vector<int> component(n_vertices, 0);
    int n_comp=0;
    for (int i:order){
        if(component[i]==0){
            n_comp++;
            DFS(graphT,visited,i,component,n_comp);
        }
    }
    std::vector<std::set<int>> graph_cond(n_comp);
    for (size_t i=0;i<n_vertices;++i){
        for (int j:graphIshod[i]){
            graph_cond[component[i]].insert(component[j]);
        }
    }
    return 0;
}
# PRESENTING CODE

Кратчайшие пути

Поиск в ширину(BFS): 


vector<int> g[maxn];

void bfs(int s) {
    queue<int> q;
    q.push(s);
    
    vector<int> d(n, -1), p(n);
    d[s] = 0;
    
    while (!q.empty()) {
        int v = q.front();
        q.pop();
        for (int u : g[v]) {
            if (d[u] == -1) {
                q.push(u);
                d[u] = d[v] + 1;
                p[u] = v;
            }
        }
    }
} 
# PRESENTING CODE

Решение

Алгоритм Дейкстры:

int main() {
	int n;
	... чтение n ...
	vector < vector < pair<int,int> > > g (n);
	... чтение графа ...
	int s = ...; // стартовая вершина
 
	vector<int> d (n, INF),  p (n);
	d[s] = 0;
	set < pair<int,int> > q;
	q.insert (make_pair (d[s], s));
	while (!q.empty()) {
		int v = q.begin()->second;
		q.erase (q.begin());
 
		for (size_t j=0; j<g[v].size(); ++j) {
			int to = g[v][j].first,
				len = g[v][j].second;
			if (d[v] + len < d[to]) {
				q.erase (make_pair (d[to], to));
				d[to] = d[v] + len;
				p[to] = v;
				q.insert (make_pair (d[to], to));
			}
		}
	}
}
# PRESENTING CODE

Алгоритм Дейкстры

void solve() {
	vector<int> d (n, INF);
	d[v] = 0;
	vector<int> p (n, -1);
	int x;
	for (int i=0; i<n; ++i) {
		x = -1;
		for (int j=0; j<m; ++j)
			if (d[e[j].a] < INF)
				if (d[e[j].b] > d[e[j].a] + e[j].cost) {
					d[e[j].b] = max (-INF, d[e[j].a] + e[j].cost);
					p[e[j].b] = e[j].a;
					x = e[j].b;
				}
	}
 
	if (x == -1)
		cout << "No negative cycle from " << v;
	else {
		int y = x;
		for (int i=0; i<n; ++i)
			y = p[y];
 
		vector<int> path;
		for (int cur=y; ; cur=p[cur]) {
			path.push_back (cur);
			if (cur == y && path.size() > 1)  break;
		}
		reverse (path.begin(), path.end());
 
		cout << "Negative cycle: ";
		for (size_t i=0; i<path.size(); ++i)
			cout << path[i] << ' ';
	}
}
# PRESENTING CODE

Алгоритм Форда-Беллмана

for (int k=0; k<n; ++k)
	for (int i=0; i<n; ++i)
		for (int j=0; j<n; ++j)
			if (d[i][k] < INF && d[k][j] < INF)
				d[i][j] = min (d[i][j], d[i][k] + d[k][j]);
# PRESENTING CODE

Алгоритм Флойда-Уоршелла

Остовные деревья

// This slide uses Auto-Animate to animate between
// two different code blocks
const distanceBetween = ( p1, p2 ) => {
 // TODO
}

distanceBetween([10,10], [50,50])
# PRESENTING CODE

Code Transitions

// This slide uses Auto-Animate to animate between
// two different code blocks
const distanceBetween = ( p1, p2 ) => {
 // TODO
}

distanceBetween([10,10], [50,50])
# PRESENTING CODE

Code Transitions

// This slide uses Auto-Animate to animate between
// two different code blocks
const distanceBetween = ( p1, p2 ) => {
 // TODO
}

distanceBetween([10,10], [50,50])
# PRESENTING CODE

Code Transitions

Code

By Fleming Kris

Code

  • 290