圖論之最小生成樹

  這次的生成樹是匆忙寫出來的,所以代碼有點難看!我用的是kruskal算法,我認爲這個比prim算法好理解一點!就是每次找未知邊的最小邊,在判斷此邊的兩個點在已知邊下是否連通——這裏就要用到我剛說的不相交集類,如果連通則放棄,不連通則加人以知邊,做完N-1次即可,下面是代碼:


#include<iostream>
#include<stdio.h>
#include<vector>
#include<queue>
using namespace std;
class Disjsets
{
private:
	vector<int>s;
public:
	Disjsets(int num):s(num)
	{
		for(int i=0;i<s.size();i++)
			s[i]=-1;
	}
	int find(int x)
	{
		if(s[x]<0)
			return x;
		else
			return s[x]=find(s[x]);

	}
	void unionSets(int root1,int root2)
	{
		if(s[root1]<s[root2])
			s[root1]=root2;
		else
		{
			if(s[root1]==s[root2])
				s[root1]--;
			s[root2]=root1;
		}
	}
	void makeDisj()
	{
			for(int i=0;i<s.size();i++)
			s[i]=-1;

	}
};
class graph
{
  struct  Edge{
   int e1,e2,w;
   Edge(int u,int v,int w):e1(u),e2(v),w(w){}
   friend bool operator <(Edge v1,Edge v2)
   {
       return v1.e1>v2.e1;
   }
  };
  struct weight{
		int ver;
		int num;
		int w;
		weight(){};
		weight(int v,int n,int ww=0):ver(v),num(n),w(ww){}
	   friend bool operator <(const weight v,const weight v1)
		{
               return	v.w>v1.w;
		}
   };
   class vertex
	{
	public:
		int num;         //點在圖中的編號
		vector<weight>L;      //與此頂點相關的邊
		vertex():num(0){}
		void merge(int x,int y)
		{
		   weight p(num,x,y);
		   L.push_back(p);

		}
	};

	vector<vertex> v;
	public:
		graph(int x)
		{
			v.resize(x);
			for(int i=0;i<x;i++)
				v[i].num=i+1;

		}

		void merge(int x,int y,int weight)
		{
			if(x!=y)
				v[x-1].merge(y,weight);

		}
		int kruskal()
		{
			priority_queue<weight>qw;
			priority_queue<Edge>Ed;
			int n=v.size();
			Disjsets D(n+1);
			int e1,e2,sum=0;
			for(int i=0;i<n;i++)
            {
                 int siz=v[i].L.size();
              	for(int j=0;j<siz;j++)
						{
						   weight tmp=v[i].L[j];
						   qw.push(tmp);
						}
            }
			weight wg;
			int edge =1;
			for(;edge<n&&!qw.empty();edge++)
			{

				while(D.find(qw.top().num)==D.find(qw.top().ver))
					               {
                                      qw.pop();
                                      if(qw.empty())
                                        return -1;
					               }
				wg=qw.top();
		   	    e1=wg.ver;
		     	e2=wg.num;
		     	sum+=wg.w;
                qw.pop();
                Edge E(e1,e2,wg.w);
                Ed.push(E);
                D.unionSets(e1,e2);
		     }
        if(edge==n)
        {
			while(!Ed.empty())
			{
				Edge ed=Ed.top();Ed.pop();
				cout<<"("<<ed.e1<<","<<ed.e2<<","<<ed.w<<") ";
			}
			cout<<endl;
        return sum;
        }
        return -1;
    }
};


int main()
{
   freopen("in.txt","r",stdin);
   freopen("out.txt","w",stdout);
    int n,m;
    while(cin>>m>>n&&m)
    {
        graph G(n);
        int u,v,w;
        while(m--)
        {
            cin>>u>>v>>w;
            G.merge(u,v,w);
            G.merge(v,u,w);
        }
      int sum=G.kruskal();
      sum==-1?cout<<"?"<<endl:cout<<sum<<endl;
    }
   fclose(stdin);
   fclose(stdout);
   return 0;
}
然後是in.txt的數據:

12 7
1 2 2
1 4 1
2 4 3
2 5 10
3 1 4
3 5 6
4 6 8
4 7 4
4 5 2
4 3 2
5 7 6
7 6 1
12 7
1 4 1
1 2 2
1 3 4
2 4 3
2 5 10
3 4 2
3 6 5
4 5 7
4 6 8
4 7 4
5 7 6
6 7 1
3 3
1 2 1
1 3 2
2 3 4
1 3
2 3 2
0 100


最後是out.txt的結果:

(1,4,1) (1,2,2) (4,3,2) (4,7,4) (4,5,2) (7,6,1) 
12
(1,4,1) (1,2,2) (4,3,2) (4,7,4) (7,6,1) (7,5,6) 
16
(1,2,1) (1,3,2) 
3
?

結果OK ,另外,交hdu的暢通工程那題也是ac的,說明確實沒有問題!

發佈了29 篇原創文章 · 獲贊 4 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章