Я написал структуру графа в виде списка ребер и пытаюсь написать алгоритм MST Крускала для него.
Вот мой код до сих пор:
#include <bits/stdc++.h>
using namespace std;
struct _ { ios_base::Init i; _() { cin.sync_with_stdio(0); cin.tie(0); } } _;
//////////////////////////////////////////////////////////////////////////////////
#define endl '\n'
#define ll long long
#define pb push_back
#define mt make_tuple
#define in(a) for (auto& i: a)
//////////////////////////////////////////////////////////////////////////////////
#define edge tuple < ll, ll, ll >
bool func (edge a, edge b) { return get<2>(a) < get<2>(b); }
struct graph
{
ll v;
vector <edge> edgelist;
void addedge (edge x) { edgelist.pb(x); }
ll find (vector <ll> parent, ll i)
{ return parent[i]==-1 ? i : find (parent, parent[i]); }
bool cycle()
{
vector <ll> parent (v);
fill (parent.begin(), parent.end(), -1);
in (edgelist)
{
ll x = find (parent, get<0>(i));
ll y = find (parent, get<1>(i));
if (x==y) return true;
else parent[x]=y;
}
return false;
}
graph mst()
{
sort (edgelist.begin(), edgelist.end(), func);
graph tree;
in(edgelist)
{
graph temp = tree;
temp.addedge(i);
if (!temp.cycle()) tree=temp;
}
return tree;
}
};int main()
{
graph g;
cin >> g.v;
ll e;
cin >> e;
for (ll i=1; i<=e; i++)
{
ll a, b, w;
cin >> a >> b >> w;
g.addedge(mt(a, b, w));
}
graph mstree = g.mst();
in(mstree.edgelist) cout << get<0>(i) << " " << get<1>(i) << " " << get<2>(i) << endl;
cout << endl;
}
/*
Sample Input
4 5
0 1 10
0 2 6
0 3 5
1 3 15
2 3 4
Sample Output
2 3 4
0 3 5
0 1 10
*/
Мой код занимает очень много времени, чтобы произвести вывод. Есть ли проблемы в моей реализации? Кроме того, если я повторяю эту задачу для нескольких графиков, моя программа падает в середине выполнения.
Мой код занимает очень много времени, чтобы произвести вывод. Есть ли
проблемы в моей реализации?
Есть несколько проблем:
Первый,
ll find (vector <ll> parent, ll i)
{ return parent[i]==-1 ? i : find (parent, parent[i]); }
Вы передаете parent
по значению это означает копирование всего массива. Передайте по ссылке (и неконстантно, так как вам нужно будет изменить ее, см. Пункт 3).
Во-вторых, в cycle()
вам не нужно проверять все ребра, вам нужно проверить только ребро, которое рассматривается в основном цикле (в mst()
). (И не устанавливать parent
в cycle()
необходимо использовать один и тот же массив во всех mst()
.)
В-третьих, читайте об «улучшениях» структуры разъединения (даже Статья в википедии объяснил все это), а именно объединение по рангу и сжатию пути. Только с теми вы достигнете ожидаемой производительности от разъединения.
Кроме того, если я повторяю эту задачу для нескольких графиков, моя программа падает
середина исполнения.
Невозможно сказать, не зная, как вам петля и каковы несколько графиков входы, которые вы используете. Тем не менее, я сильно подозреваю, что переполнение стека на графиках даже среднего размера при прохождении parent
по значению, таким образом быстро потребляя стек.
Других решений пока нет …