最小生成树

Overview


There are two different ways to achieve this algorithm.

Prim


From a single node s, and we can devide the whole graph into two separate parts. One is the tree formed from s, the other is the remain part of the graph. Every time, we always choose the nodes p that is the closet nodes from the remain part after exclude the nodes on the tree. Use Heap may help us makes the algorithm more efficiency.

Kruskal


Kruskal is also a greedy algorithm. We can use Union-Find set to help us complete our operation.

OJ Practise


POJ 1251


This problem I solved it with Prim algorithm:

#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;

const int INF= 1e9;
const int maxn= 30;
class prim{
	int n;
	int w[maxn];
	struct edge{
		int to;
		int cst;
		edge(int t, int cs) : to(t), cst(cs){}
	};
	vector<edge> G[maxn];
	typedef pair<int, int> P;
	priority_queue<P, vector<P>, greater<P> > Q;
	int done[maxn];
	int sum;
	void Init()
	{
		for (int i= 0; i< n; ++i){
			w[i]= INF;
		}
		memset(done, 0, sizeof(done));
		sum= 0;
	}
	int Prim(int s)
	{
		w[s]= 0;
		Q.push(P(0, s));

		while (!Q.empty()){
			P tmp= Q.top();
			Q.pop();
			int dest= tmp.second;
			if (done[dest]){
				continue;
			}
			done[dest]= 1;
			sum+= tmp.first;
			for (int i= 0; i< int(G[dest].size()); ++i){
				edge e= G[dest][i];
				if (!done[e.to] && w[e.to]> e.cst){
					w[e.to]=  e.cst;
					Q.push(P(w[e.to], e.to));
				}
			}
		}

		return sum;
	}
	void AddEdge(int from, int to, int cst)
	{
		G[from].push_back(edge(to, cst));
		G[to].push_back(edge(from, cst));
	}
	void Read(int idx, int k)
	{
		char nv;
		int nvi, wt;
		for (int j= 0; j< k; ++j){
			cin>>nv>>wt;
			nvi= nv-'A';
			AddEdge(idx, nvi, wt);
		}
	}
public:
	void Solve()
	{
		while (cin>>n && n){
			Init();
			for (int i= 0; i< n-1; ++i){
				char idx;
				int k;
				cin>>idx>>k;
				Read(int(idx-'A'), k);
			}
			Prim(0);
			for (int i= 0; i< maxn; ++i){
				G[i].clear();
			}			
			cout<<sum<<endl;
		}
	}
};

int main()
{
	prim poj1251;
	poj1251.Solve();
	return 0;
}

ZOJ 1586


First code, I correct it to AC.

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

const int maxnum= 1e6;

struct edge{
    int from;
    int to;
    int cst;
};
edge egs[maxnum];
int ans;
int par[maxnum];
int w[maxnum];

void Init(int n)
{
    ans= 0;
    memset(w, 0, sizeof(w));
    for (int i= 0; i< n; ++i){
        par[i]= i;
    }
}
inline int Find(int x)
{
    if (x== par[x]){
        return par[x];
    }
    return par[x]= Find(par[x]);
}
inline void Union(int x, int y)
{
    x= Find(x);
    y= Find(y);
    if (x== y){
        return;
    }
    if (x< y){
        par[y]= x;
    }
    else{
        par[x]= y;
    }
}
inline bool cmp(edge a, edge b)
{
    return a.cst< b.cst;
}
void Kruskal(const int n, const int lth)
{
	sort(egs, egs+lth, cmp);

	int n_eg= 0;
	for (int i= 0; i< lth; ++i){
		if (Find(egs[i].from)!= Find(egs[i].to)){
			Union(egs[i].from, egs[i].to);
			ans+= egs[i].cst;
			++n_eg;
		}
		if (n-1== n_eg){
			break;
		}
	}
}

int main()
{
    int kase;
    scanf("%d", &kase);
    while (kase--){
        int n, adpt, lth;
        scanf("%d", &n);
        Init(n);

        for (int i= 0; i< n; ++i){
            scanf("%d", w+i);
        }
        lth= 0;
        for (int i= 0; i< n; ++i){
            for (int j= 0; j< n; ++j){
                scanf("%d", &adpt);
                if (i< j){
                    egs[lth].from= i;
                    egs[lth].to= j;
                    egs[lth].cst= adpt+w[i]+w[j];
                    ++lth;
                }
            }
        }
        Kruskal(n, lth);
        cout<<ans<<endl;
    }
    return 0;
}

AC Code

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxnum= 1e6;

struct edge{
    int from, to;
    int cst;
    bool operator <  (const edge &eg) const
    {
        return cst< eg.cst;
    }
};
edge egs[maxnum];
int ans;
int par[maxnum];
int adpt[maxnum];

void Init(int n)
{
    memset(egs, 0, sizeof(egs));
    memset(adpt, 0, sizeof(adpt));
    ans= 0;
    for (int i= 0; i< n; ++i){
        par[i]= i;
    }
}
int Find(int x)
{
    if (x== par[x]){
        return x;
    }
    return par[x]= Find(par[x]);
}
void Union(int x, int y)
{
    x= Find(x);
    y= Find(y);
    if (x== y){
        return;
    }

    if (x< y){
        par[y]= x;
    }
    else{
        par[x]= y;
    }
}
int Kruskal(int n, int lth)
{
    sort(egs, egs+lth);
    int n_eg= 0;
    for (int i= 0; i< lth; ++i){
        if (Find(egs[i].from)!= Find(egs[i].to)){
            ans+= egs[i].cst;
            ++n_eg;
            Union(egs[i].from, egs[i].to);
        }
        if (n-1== n_eg){
            break;
        }
    }

    return ans;
}

int main()
{
    int kase;
    scanf("%d", &kase);
    while (kase--){
        int n, tmp, lth= 0;
        scanf("%d", &n);
        Init(n);

        for (int i= 0; i< n; ++i){
            scanf("%d", adpt+i);
        }
        for (int i= 0; i< n; ++i){
            for (int j= 0; j< n; ++j){
                scanf("%d", &tmp);
                egs[lth].from= i;
                egs[lth].to= j;
                if (i!= j){
                    egs[lth].cst= tmp+ adpt[i]+adpt[j];
                }
                ++lth;
            }
        }
        Kruskal(n, lth);
        cout<<ans<<endl;
    }
    return 0;
}

posted @ 2019-12-09 17:10  IdiotNe  阅读(77)  评论(0)    收藏  举报