HDU - 1863:暢通工程

暢通工程

來源:HDU

標籤:最小生成樹,合併查找算法

參考資料:

相似題目:

題目

省政府“暢通工程”的目標是使全省任何兩個村莊間都可以實現公路交通(但不一定有直接的公路相連,只要能間接通過公路可達即可)。經過調查評估,得到的統計表中列出了有可能建設公路的若干條道路的成本。現請你編寫程序,計算出全省暢通需要的最低成本。

輸入

測試輸入包含若干測試用例。每個測試用例的第1行給出評估的道路條數 N、村莊數目M ( < 100 );隨後的 N 行對應村莊間道路的成本,每行給出一對正整數,分別是兩個村莊的編號,以及此兩村莊間道路的成本(也是正整數)。爲簡單起見,村莊從1到M編號。當N爲0時,全部輸入結束,相應的結果不要輸出。

輸出

對每個測試用例,在1行裏輸出全省暢通需要的最低成本。若統計數據不足以保證暢通,則輸出“?”。

輸入樣例

3 3
1 2 1
1 3 2
2 3 4
1 3
2 3 2
0 100

輸出樣例

3
?

參考代碼

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

const int MAXN=105;

struct UnionFind{
	int ufset[MAXN];
	int size; //連通分量個數 
	
	int init(int N){ //N爲節點數 
		size=N;
		for(int i=1;i<=N;i++){ //節點標號從1開始 
			ufset[i]=i;
		}
	}

	int find(int v){
		while(v!=ufset[v]) v=ufset[v];
		return v;
	}
	
	void join(int v,int u){
		int ra=find(v);
		int rb=find(u);
		if(ra==rb) return;
		ufset[ra]=rb;
		size--; 
	}
};

struct Edge{ 
    int u; //邊的一個頂點
	int v; //邊的另一個頂點 
    int w; //邊的權值 
    Edge(int u,int v,int w):u(u),v(v),w(w){}
    bool operator < (const Edge &e) const {
        return w>e.w;
    }
};

struct Prim{ //Prim算法,計算最小生成樹,適用有向或無向圖 
	vector<Edge> adj[MAXN]; //agj[v]:與v相連的邊 
	priority_queue<Edge> pq; //優先隊列,存放橫切邊 
	vector<Edge> mst; //最小生成樹 
	bool vis[MAXN]; //訪問標誌
	
	void prim(int s){ //從起點s開始 
		visit(s); 
	    while(!pq.empty()){
	        Edge e=pq.top();
	        pq.pop();
	        if(vis[e.u] && vis[e.v]) continue;
	        mst.push_back(e);
	        if(!vis[e.u]) visit(e.u);
	        if(!vis[e.v]) visit(e.v);
	    }
	}
	
	void init(){ //初始化 
		for(int i=0;i<MAXN;i++) adj[i].clear();
		while(!pq.empty()) pq.pop();
		mst.clear();
		memset(vis,0,sizeof(vis));
	}
	
	void addEdge(int u,int v,int w){
		adj[u].push_back(Edge(u,v,w));
	}
	
	void visit(int u){ //設置訪問標誌,並將與v相鄰結點(未被訪問)的邊加入優先隊列中
	    vis[u]=true;
	    for(vector<Edge>::iterator i=adj[u].begin(); i!=adj[u].end();i++)
	        if(!vis[(*i).v]) pq.push(*i);
	}
};

UnionFind uf;
Prim prim;
int N,M;
int u,v,w;

int main(){
	while(scanf("%d%d",&N,&M)==2 && N){
		uf.init(M);
		prim.init();
		for(int i=0;i<N;i++){
			scanf("%d%d%d",&u,&v,&w);
			prim.addEdge(u,v,w);
			prim.addEdge(v,u,w);
			uf.join(u,v);
		}
		if(uf.size!=1) printf("?\n");
		else {
			int ans=0;
			prim.prim(1);
			for(int i=0;i<prim.mst.size();i++){
				ans+=prim.mst[i].w;
			}
			printf("%d\n",ans);
		}
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章