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
#include
#include
#include
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;
}

你可能感兴趣的:(【记录】算法题解)